diff --git a/media/logo.png b/media/logo.png index e97c3ae..17100f0 100644 Binary files a/media/logo.png and b/media/logo.png differ diff --git a/package.json b/package.json index d0dce26..fef8456 100644 --- a/package.json +++ b/package.json @@ -18,7 +18,8 @@ ], "activationEvents": [ "onLanguage:json", - "onLanguage:jsonc" + "onLanguage:jsonc", + "onView:gradefast-home" ], "main": "./out/extension.js", "contributes": { @@ -28,10 +29,26 @@ "id": "package-explorer", "title": "GradeFast", "icon": "media/logo.svg" - } + }, + { + "id": "gradefast", + "title": "GradeFast", + "icon": "media/logo.png" + } ] }, "views": { + "gradefast":[ + { + "id": "gradefast-home", + "name": "Home", + "type": "tree" + }, + { + "id": "gradefast-section", + "name": "Section" + } + ], "package-explorer": [ { "id": "nodeDependencies", @@ -43,7 +60,33 @@ "explorer": [ ] }, + "viewsWelcome": [ + { + "view": "gradefast-home", + "contents": "Open a student's assignment directory to begin grading. \n[Pick a folder](command:workbench.action.files.openFolder)\n[Generate Report](command:extension.generateReport)" + } + ], "commands": [ + { + "command": "extension.generateReport", + "title": "Generate Report" + }, + { + "command": "mywiki.editNote", + "title": "Edit", + "icon": { + "dark": "resources/edit_inverse.svg", + "light": "resources/edit.svg" + } + }, + { + "command": "mywiki.saveNote", + "title": "Save" + }, + { + "command": "mywiki.cancelsaveNote", + "title": "Cancel" + }, { "command": "mywiki.createNote", "title": "Create Note", @@ -125,6 +168,18 @@ ], "view/item/context": [ ], + "comments/comment/context": [ + { + "command": "mywiki.cancelsaveNote", + "group": "inline@1", + "when": "commentController == comment-sample" + }, + { + "command": "mywiki.saveNote", + "group": "inline@2", + "when": "commentController == comment-sample" + } + ], "comments/commentThread/context": [ { "command": "mywiki.createNote", @@ -132,6 +187,13 @@ "when": "commentController == comment-sample && commentThreadIsEmpty" } ], + "comments/comment/title": [ + { + "command": "mywiki.editNote", + "group": "group@1", + "when": "commentController == comment-sample" + } + ], "comments/commentThread/title": [ { "command": "mywiki.deleteNote", diff --git a/report_generator/report_generator/main.py b/report_generator/report_generator/main.py index 9c9ac2a..8648bdb 100644 --- a/report_generator/report_generator/main.py +++ b/report_generator/report_generator/main.py @@ -1,10 +1,10 @@ -""" -Call with "python3 report_generator/main.py path/to/json" -""" - +''' +call with "python3 report_generator/main.py path/to/json" +''' from dotenv import load_dotenv -from pylatex import Document, Section, NewPage -from pylatex.utils import NoEscape +from pylatex import Document, Section, LineBreak, NewPage, PageStyle, Package +from pylatex.base_classes import Environment +from pylatex.utils import bold, NoEscape import os from os import path import sys @@ -12,83 +12,76 @@ from util.parse_json import json_to_dict -error_links = { - 'Improper Capitalized Primitive Type': 'https://www.oracle.com/java/technologies/javase/codeconventions-namingconventions.html', - 'Improper Method Name': 'https://www.oracle.com/java/technologies/javase/codeconventions-namingconventions.html', - 'Too many statements on this line, revise': 'https://www.oracle.com/java/technologies/javase/codeconventions-declarations.html', - 'Improper Class Or Interface': 'https://www.oracle.com/java/technologies/javase/codeconventions-namingconventions.html' -} + +class syntax_code(Environment): + _latex_name = 'minted' + #packages = [Package('minted')] + start_arguments = 'java' + escape = False + content_separator = '\n' + def __init__(self, *, options=None, arguments=None, start_arguments=start_arguments, **kwargs): + super().__init__(options=options, arguments=arguments, start_arguments=start_arguments, **kwargs) + +class syntax_code(Environment): + _latex_name = 'minted' + #packages = [Package('minted')] + start_arguments = 'java' + escape = False + content_separator = '\n' + def __init__(self, *, options=None, arguments=None, start_arguments=start_arguments, **kwargs): + super().__init__(options=options, arguments=arguments, start_arguments=start_arguments, **kwargs) def format_doc(): - geometry_options = { - 'margin': '0.5in' - } - - doc = Document(geometry_options=geometry_options) - doc.change_document_style('empty') - return doc + + geometry_options = { + 'margin': '0.5in' + } + + doc = Document(geometry_options=geometry_options) + doc.change_document_style('empty') + doc.packages.append(Package(name='minted')) + doc.packages.append(Package(name='setspace')) + doc.preamble.append(NoEscape(r'\SetSinglespace{1.1}')) + doc.preamble.append(NoEscape(r'\singlespacing')) + return doc + +def assemble_pdf(json_file_path: str, assignment_path: str, out_dir: str='./out/out'): + assignment = open(assignment_path).read().splitlines() -def assemble_pdf(json_file_path: str): - with open(json_file_path, 'r') as f: - data = json.load(f) + # Load JSON data from file + with open(json_file_path, 'r') as f: + data = json.load(f) + + data: dict + # load path to pdflatex + dotenv_path = path.join(path.dirname(__file__), '.env') + load_dotenv(dotenv_path) + PDFLATEX_PATH = os.environ.get('PDFLATEX_PATH') # load path to pdflatex dotenv_path = path.join(path.dirname(__file__), '.env') load_dotenv(dotenv_path) PDFLATEX_PATH = os.environ.get('PDFLATEX_PATH') - doc = format_doc() - - keys = list(data.keys()) - with doc.create(Section(NoEscape(r'\centerline{' "Student A" + '}'), numbering=False)): - doc.append(NoEscape(r'\centerline{/src/file.java} \n')) - doc.append('\n') - doc.append('\n\n') - - for key in keys: - doc.append(NoEscape(f"Line: {key}")) - doc.append('\n') - if data[key] is not None: - values = data[key] - values = [str(value).strip("'") for value in values] - error_type = "Error Type: " + ", ".join(values) - doc.append(NoEscape(error_type)) - doc.append('\n') - else: - doc.append(NoEscape("Error Type:")) - doc.append('\n') - - doc.append(NoEscape("Description:")) - doc.append('\n') - doc.append(NoEscape("Additional Notes:")) - doc.append('\n') - doc.append('\n') - - doc.append(NewPage()) - doc.append(Section(NoEscape(r'\underline{Additional Resources:}'), numbering=False)) - doc.append('\n') - doc.append('\n') - - added_errors = set() - - for key in keys: - if data[key] is not None: - values = data[key] - unique_values = list(set([str(value).strip("'") for value in values])) # Removes duplicates - for error_name in unique_values: - error_message = error_name - if error_message not in added_errors: - if error_name in error_links: - link = error_links[error_name] - doc.append(NoEscape(error_message + r': \underline{\href{' + link + r'}{link}}\n')) - doc.append('\n') - else: - doc.append('- ' + error_message + '\n') - added_errors.add(error_message) - else: - doc.append("\n") + keys = list(data.keys()) + print(keys) + with doc.create(Section(NoEscape(r'\centerline{Code Report}'), numbering=False)): + for count, line in enumerate(assignment): + if data.get(str(count + 1)) is not None: + text = data.get(str(count + 1)) + doc.append(str(text)) + else: + with doc.create(syntax_code()): + # text = ''.join([line]) + text = (line) + doc.append(text) + + doc.generate_pdf(out_dir, clean_tex=False, compiler=PDFLATEX_PATH, compiler_args=['-shell-escape']) + # doc = format_doc() + # doc.append(NewPage()) + # doc.generate_pdf('out/out', clean_tex=False, compiler='pdflatex', silent=False) doc.generate_pdf('report_out/report_out', clean_tex=False, compiler=PDFLATEX_PATH) if __name__ == '__main__': - assemble_pdf(sys.argv[1]) + assemble_pdf(sys.argv[1], sys.argv[2]) diff --git a/src/badSwitch.ts b/src/badSwitch.ts index 38eac7a..d7b79ed 100644 --- a/src/badSwitch.ts +++ b/src/badSwitch.ts @@ -1,3 +1,4 @@ +/* eslint-disable prefer-const */ import * as vscode from 'vscode'; export function badSwitch(myMap: Map) { diff --git a/src/cursorPosition.ts b/src/cursorPosition.ts new file mode 100644 index 0000000..4b4c224 --- /dev/null +++ b/src/cursorPosition.ts @@ -0,0 +1,11 @@ +import * as vscode from 'vscode'; + +export function cursorPosition() { + const editor = vscode.window.activeTextEditor; + if (editor === undefined) { + return; + } + const doc = editor.document; + const position = editor.selection.active; + return doc.lineAt(position); +} \ No newline at end of file diff --git a/src/extension.ts b/src/extension.ts index 2f841bf..6f0b710 100644 --- a/src/extension.ts +++ b/src/extension.ts @@ -1,6 +1,7 @@ 'use strict'; import * as vscode from 'vscode'; +import * as path from 'path'; import { NoteCommentController } from './noteComment'; import { findCapitalizedPrimitiveTypes } from './findCapitalizedPrimitiveTypes'; import { findLowercaseClassOrInterface } from './findLowercaseClassOrInterface'; @@ -21,6 +22,14 @@ const filePath = 'C:\\Users\\senla\\OneDrive\\Documents\\capstone\\gradeFast-1.0 export function activate(context: vscode.ExtensionContext) { + vscode.commands.executeCommand('workbench.action.files.setActiveEditorReadonlyInSession'); + + const pdfMaker = new MakePdf(context); + + const generateReport = vscode.commands.registerCommand('extension.generateReport', () => { + pdfMaker.runPython(); + }); + const disposable = vscode.commands.registerCommand('extension.findCapitalizedPrimitiveTypes', () => { findCapitalizedPrimitiveTypes(myMap); } ); @@ -79,3 +88,52 @@ export function activate(context: vscode.ExtensionContext) { NoteCommentController.registerCommands(context); } + +class MakePdf { + // private _outputchannel: vscode.OutputChannel; + // private _context: vscode.ExtensionContext; + private _path: string; + private _activeFileName: string | undefined; + private _activeFilePath: string | undefined; + private _activeDir: string | undefined; + // private data: string = JSON.stringify() + + + constructor(context: vscode.ExtensionContext) { + // this._context = context; + this._path = filePath; + this._activeFileName = vscode.window.activeTextEditor?.document.fileName; + if (this._activeFileName !== undefined) { + this._activeFilePath = path.join(this._activeFileName); + } + if (vscode.workspace.workspaceFolders !== undefined) { + this._activeDir = vscode.workspace.workspaceFolders[0].uri.path; + } + // this._outputchannel = vscode.window.createOutputChannel() + } + + public runPython(): void { + console.log(this); + if (this._activeFileName !== undefined && this._activeDir !== undefined) { + const exp = /.*(?=\.)/; + let pdfName = this._activeFileName.match(exp)?.[0]; + + if (pdfName === undefined) { return; } + + pdfName = this._activeDir.concat(pdfName); + console.log(pdfName); + const pdfCommand = `python3 /Users/mihaisiia/GradeFast/gradeFast-1.0/report_generator/report_generator/main.py ${ this._path } ${ this._activeDir + this._activeFilePath } ${ pdfName }`; + console.log(pdfCommand); + const child = exec(pdfCommand); + + child.on('error', (e) => { + console.error(e); + }); + + child.on('exit', (e) => { + // this._runPython(); + console.log(e); + }); + } + } +} diff --git a/src/findCapitalizedPrimitiveTypes.ts b/src/findCapitalizedPrimitiveTypes.ts index a53f69d..fb9b2ef 100644 --- a/src/findCapitalizedPrimitiveTypes.ts +++ b/src/findCapitalizedPrimitiveTypes.ts @@ -1,7 +1,7 @@ import * as vscode from 'vscode'; import * as fs from 'fs'; -const outputFile = '/Users/willscomputer/gradeFast-1.0/src/errorTxt'; +const outputFile = '/Users/mihaisiia/GradeFast/gradeFast-1.0/src/errorTxt'; export function findCapitalizedPrimitiveTypes(myMap: Map): Map { vscode.window.showInformationMessage('Naming Convention Mistake!! Highlighted in RED'); diff --git a/src/noteComment.ts b/src/noteComment.ts index 6f1cd11..6d3e8e9 100644 --- a/src/noteComment.ts +++ b/src/noteComment.ts @@ -1,20 +1,23 @@ +import { userInfo } from 'os'; import * as vscode from 'vscode'; +import { cursorPosition } from './cursorPosition'; //This class is a NoteComment object that is used inside the commentController API. -let commentId = 1; +// let commentId = 1; class NoteComment implements vscode.Comment { id: number; label: string | undefined; savedBody: string | vscode.MarkdownString; // for the Cancel button constructor( + public commentId: number, public body: string | vscode.MarkdownString, public mode: vscode.CommentMode, public author: vscode.CommentAuthorInformation, public parent?: vscode.CommentThread, public contextValue?: string ) { - this.id = ++commentId; + this.id = commentId; this.savedBody = this.body; } } @@ -22,17 +25,78 @@ class NoteComment implements vscode.Comment { class NoteCommentController { private static replyNote(reply: vscode.CommentReply) { const thread = reply.thread; - const newComment = new NoteComment(reply.text, vscode.CommentMode.Preview, { name: 'vscode' }, thread, thread.comments.length ? 'canDelete' : undefined); + const newComment = new NoteComment(reply.thread.range.end.line, reply.text, vscode.CommentMode.Preview, { name: userInfo().username }, thread, thread.comments.length ? 'canDelete' : undefined); thread.canReply = false; thread.comments = [...thread.comments, newComment]; + console.log(newComment.id); + // console.log(cursorPosition()); } //These two commands allow the user to create notes and delete them. static registerCommands(context: vscode.ExtensionContext) { context.subscriptions.push(vscode.commands.registerCommand('mywiki.createNote', (reply: vscode.CommentReply) => { - NoteCommentController.replyNote(reply); + // eslint-disable-next-line no-unsafe-optional-chaining + const lineNumber = vscode.window.activeTextEditor?.selection.active.line; + if (lineNumber !== undefined) { + console.log(lineNumber); + } + NoteCommentController.replyNote(reply); + console.log(vscode.workspace.onDidChangeTextDocument); + })); + context.subscriptions.push(vscode.commands.registerCommand('mywiki.cancelsaveNote', (comment: NoteComment) => { + if (!comment.parent) { + return; + } + + comment.parent.comments = comment.parent.comments.map(cmt => { + if ((cmt as NoteComment).id === comment.id) { + cmt.body = (cmt as NoteComment).savedBody; + cmt.mode = vscode.CommentMode.Preview; + } + + return cmt; + }); + })); + + context.subscriptions.push(vscode.commands.registerCommand('mywiki.saveNote', (comment: NoteComment) => { + if (!comment.parent) { + return; + } + const lineNumber = vscode.window.activeTextEditor?.selection.active.line; + if (lineNumber !== undefined) { + console.log(lineNumber); + } + + comment.parent.comments = comment.parent.comments.map(cmt => { + if ((cmt as NoteComment).id === comment.id) { + (cmt as NoteComment).savedBody = cmt.body; + cmt.mode = vscode.CommentMode.Preview; + } + + return cmt; + }); + })); + + context.subscriptions.push(vscode.commands.registerCommand('mywiki.editNote', (comment: NoteComment) => { + if (!comment.parent) { + return; + } + const lineNumber = vscode.window.activeTextEditor?.selection.active.line; + if (lineNumber !== undefined) { + console.log(lineNumber); + } + + comment.parent.comments = comment.parent.comments.map(cmt => { + if ((cmt as NoteComment).id === comment.id) { + cmt.mode = vscode.CommentMode.Editing; + } + + return cmt; + }); + })); + context.subscriptions.push(vscode.commands.registerCommand('mywiki.deleteNote', (thread: vscode.CommentThread) => { thread.dispose(); }));