Skip to content

Commit

Permalink
Add the capability in the pg problem editor to pg perltidy code.
Browse files Browse the repository at this point in the history
This adds a new tab to the PG problem editor (unless editing a course
configuration file).  The tab contains basic information about what it
does, but if the "Tidy Code" button is pressed it perltidies the code in
the CodeMirror editor window.  The tidied code is also saved to the
temprorary file.

The actual tidying is done by a new webwork webservice action (not a
form submission).  If errors occur, they are shown in the renderer
window.

The webwork webwservice depends on a new PG module defined in a
corresponding PG pull request (see openwebwork/pg#868).
  • Loading branch information
drgrice1 committed Jul 3, 2023
1 parent b848e11 commit 025b739
Show file tree
Hide file tree
Showing 7 changed files with 88 additions and 8 deletions.
8 changes: 4 additions & 4 deletions conf/snippets/newProblem.pg
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,9 @@
DOCUMENT();

loadMacros(
"PGstandard.pl", # Standard macros for PG language
"PGML.pl", # PGML markup and Math Objects
"PGcourse.pl", # Customization file for the course
"PGstandard.pl", # Standard macros for PG language
"PGML.pl", # PGML markup and Math Objects
"PGcourse.pl", # Customization file for the course
);

# Uncomment the following if you don't want to show which
Expand All @@ -34,6 +34,6 @@ END_PGML
BEGIN_PGML_SOLUTION
You could type [|pi|]* or [|3.14|]*, or [|22/7|]*,
among other options.
END_PGML_SOLUTION
END_PGML_SOLUTION

ENDDOCUMENT();
42 changes: 42 additions & 0 deletions htdocs/js/PGProblemEditor/pgproblemeditor.js
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,49 @@
?.addEventListener('change', () => deleteBackupCheck.checked = true);
}

// Send a request to the server to perltidy the current PG code in the CodeMirror editor.
const tidyPGCode = () => {
const request_object = {
user: document.getElementById('hidden_user')?.value,
courseID: document.getElementsByName('courseID')[0]?.value,
key: document.getElementById('hidden_key')?.value
};

request_object.rpc_command = 'tidyPGCode';
request_object.pgCode = webworkConfig?.pgCodeMirror?.getValue()
?? document.getElementById('problemContents')?.value ?? '';

fetch(webserviceURL, { method: 'post', mode: 'same-origin', body: new URLSearchParams(request_object) })
.then((response) => response.json())
.then((data) => {
if (data.result_data.status) {
if (data.result_data.errors) {
renderArea.innerHTML = '<div class="alert alert-danger p-1 m-2">' +
'<p class="fw-bold">PG perltidy errors:</p>' +
'<pre><code>' +
data.result_data.errors
.replace(/^[\s\S]*Begin Error Output Stream\n\n/, '')
.replace(/\n\d*: To save a full \.LOG file rerun with -g/, '') +
'</code></pre>';
}
showMessage('Errors occurred perltidying code.', false);
return;
}
if (webworkConfig?.pgCodeMirror) webworkConfig.pgCodeMirror.setValue(data.result_data.tidiedPGCode);
else document.getElementById('problemContents').value = data.result_data.tidiedPGCode;
saveTempFile();
showMessage('Successfuly perltidied code.', true);
})
.catch((err) => showMessage(`Error: ${err?.message ?? err}`));
};

document.getElementById('take_action')?.addEventListener('click', async (e) => {
if (document.getElementById('current_action')?.value === 'pgtidy') {
e.preventDefault();
tidyPGCode();
return;
}

const actionView = document.getElementById('view');
const editorForm = document.getElementById('editor');

Expand Down
11 changes: 7 additions & 4 deletions lib/WeBWorK/ContentGenerator/Instructor/PGProblemEditor.pm
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,7 @@ the submit button pressed (the action).
Make this set header for: action = add_problem
Revert: action = revert
Generate Hardcopy: action = hardcopy
Tidy Code: action = pgtidy
An undefined or invalid action is interpreted as an initial edit of the file.
Expand All @@ -115,13 +116,14 @@ use WeBWorK::Utils::Instructor qw(assignProblemToAllSetUsers addProblemToSet);
use constant DEFAULT_SEED => 123456;

# Editor tabs
use constant ACTION_FORMS => [qw(view hardcopy save save_as add_problem revert)];
use constant ACTION_FORMS => [qw(view hardcopy pgtidy save save_as add_problem revert)];
use constant ACTION_FORM_TITLES => {
view => x('View/Reload'),
hardcopy => x('Generate Hardcopy'),
add_problem => x('Append'),
pgtidy => x('Tidy Code'),
save => x('Save'),
save_as => x('Save As'),
add_problem => x('Append'),
revert => x('Revert'),
};

Expand Down Expand Up @@ -778,9 +780,10 @@ sub view_handler ($c) {
return;
}

# The hardcopy action is handled by javascript. This is provided just in case
# something goes wrong and the action gets called.
# The hardcopy and pgtidy actions are handled by javascript. These are provided just in case
# something goes wrong and the actions are called.
sub hardcopy_action { }
sub pgtidy_action { }

sub add_problem_handler ($c) {
my $db = $c->db;
Expand Down
1 change: 1 addition & 0 deletions lib/WebworkWebservice.pm
Original file line number Diff line number Diff line change
Expand Up @@ -268,6 +268,7 @@ sub command_permission {
putUserProblem => 'modify_student_data',
putProblemVersion => 'modify_student_data',
putPastAnswer => 'modify_student_data',
tidyPGCode => 'access_instructor_tools',

# WebworkWebservice::RenderProblem
renderProblem => 'proctor_quiz_login',
Expand Down
20 changes: 20 additions & 0 deletions lib/WebworkWebservice/ProblemActions.pm
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ use warnings;
use Data::Structure::Util qw(unbless);

use WeBWorK::Debug;
use WeBWorK::PG::Tidy qw(pgtidy);

sub getUserProblem {
my ($invocant, $self, $params) = @_;
Expand Down Expand Up @@ -133,4 +134,23 @@ sub putPastAnswer {
};
}

sub tidyPGCode {
my ($invocant, $self, $params) = @_;

debug('in tidyPGCode');

local @ARGV = ();

my $code = $params->{pgCode};
my $tidiedPGCode;
my $errors;

my $result = pgtidy(source => \$code, destination => \$tidiedPGCode, errorfile => \$errors);

return {
ra_out => { tidiedPGCode => $tidiedPGCode, status => $result, errors => $errors },
text => 'Tidied code'
};
}

1;
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
% # Hardcopy headers are previewed from the hardcopy generation tab.
% last if $c->{file_type} eq 'course_info';
%
<div class="row">
<p><%= maketext('Reformat the code using perltidy.') =%></p>
</div>
8 changes: 8 additions & 0 deletions templates/HelpFiles/InstructorPGProblemEditor.html.ep
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,14 @@
. 'generating the PDF file using pdflatex.') =%>
</dd>

<dt><%= maketext('Tidy Code') %></dt>
<dd>
<%= maketext('Reformat the code using perltidy. This will change the code in the editor window, and save '
. 'changes to the temporary file. In some cases (if the code contains backslashes or double tildes) this '
. 'can result in odd spacing in the code. So make sure to inspect the formatted code, and edit further or '
. 'revert if needed.') =%>
</dd>

<dt><%= maketext('Save') %></dt>
<dd>
<%= maketext('Save the contents of the editor window to the file on disk and re-render the problem. If '
Expand Down

0 comments on commit 025b739

Please sign in to comment.