Я унаследовал некоторый код, в котором у автора было отвращение к точкам с запятой. Можно ли исправить все сообщения mlint за один раз (по крайней мере, все с автоматическим исправлением), вместо того, чтобы щелкнуть каждый из них и нажать ALT + ENTER?
Есть ли способ исправить все сообщения MintLab mlint сразу?
Ответ 1
ПРИМЕЧАНИЕ: В этом ответе используется функция MLINT, которая больше не рекомендуется в более новых версиях MATLAB. Более предпочтительной является функция CHECKCODE, а приведенный ниже код будет работать, просто заменив вызов MLINT вызовом этой новой функции.
Я вообще не знаю, как вообще можно автоматически исправить код на основе MLINT сообщений. Однако в вашем конкретном случае есть автоматический способ добавить точки с запятой в строки, которые вызывают предупреждение MLINT.
Сначала начнем с этого примера script junk.m
:
a = 1
b = 2;
c = 'a'
d = [1 2 3]
e = 'hello';
Первая, третья и четвертая строки предоставят вам MLINT предупреждающее сообщение "Завершить инструкцию с точкой с запятой для подавления вывода (в пределах a script).". Используя функциональную форму MLINT, мы можем найти строки в файле, где это предупреждение происходит. Затем мы можем прочитать все строки кода из файла, добавить точку с запятой в концы строк, где это предупреждение, и записать строки кода обратно в файл. Вот код для этого:
%# Find the lines where a given mlint warning occurs:
fileName = 'junk.m';
mlintID = 'NOPTS'; %# The ID of the warning
mlintData = mlint(fileName,'-id'); %# Run mlint on the file
index = strcmp({mlintData.id},mlintID); %# Find occurrences of the warnings...
lineNumbers = [mlintData(index).line]; %# ... and their line numbers
%# Read the lines of code from the file:
fid = fopen(fileName,'rt');
linesOfCode = textscan(fid,'%s','Delimiter',char(10)); %# Read each line
fclose(fid);
%# Modify the lines of code:
linesOfCode = linesOfCode{1}; %# Remove the outer cell array encapsulation
linesOfCode(lineNumbers) = strcat(linesOfCode(lineNumbers),';'); %# Add ';'
%# Write the lines of code back to the file:
fid = fopen(fileName,'wt');
fprintf(fid,'%s\n',linesOfCode{1:end-1}); %# Write all but the last line
fprintf(fid,'%s',linesOfCode{end}); %# Write the last line
fclose(fid);
И теперь файл junk.m
должен иметь точки с запятой в конце каждой строки. Если вы хотите, вы можете поместить вышеуказанный код в функцию, чтобы вы могли легко запустить его в каждом файле вашего унаследованного кода.
Ответ 2
Чтобы решить эту проблему в общем случае для всех доступных действий autofix, мы должны прибегать к ужасно недокументированным java-методам. Реализация mlint
(и теперь checkcode
) использует mlintmex
(встроенный, а не mexfile, как следует из названия), который просто возвращает вывод текста из linter. Никаких автофиксаций не обнаружено; даже номера строк и столбцов испускаются как обычный текст. Кажется, это то же самое, что и выход бинарника mlint в установке Matlab ($(matlabroot)/bin/$(arch)/mlint
)
Итак, мы должны вернуться к реализации Java, используемой самим редактором. Остерегайтесь: здесь следует ужасно недокументированный код для R2013a.
%// Get the java component for the active matlab editor
ed = matlab.desktop.editor.getActive().JavaEditor.getTextComponent();
%// Get the java representation of all mlint messages
msgs = com.mathworks.widgets.text.mcode.MLint.getMessages(ed.getText(),ed.getFilename())
%// Loop through all messages and apply the autofix, if it exits
%// Iterate backwards to try to prevent changing the location of subsequent
%// fixes... but two nearby fixes could still mess each other up.
for i = msgs.size-1:-1:0
if msgs.get(i).hasAutoFix()
com.mathworks.widgets.text.mcode.analyzer.CodeAnalyzerUtils.applyAutoFixes(ed,msgs.get(i).getAutoFixChanges);
end
end
ИЗМЕНИТЬ: AHA! Вы можете получить бинарник mlint, чтобы вернуть исправления с флагом -fix
... и это относится и к встроенному checkcode
! Все еще недокументирован (насколько я знаю), но, вероятно, гораздо более надежный, чем выше:
>> checkcode(matlab.desktop.editor.getActiveFilename(),'-fix')
L 2 (C 3): Terminate statement with semicolon to suppress output (in functions). (CAN FIX)
----FIX MESSAGE <Add a semicolon.>
----CHANGE MESSAGE L 2 (C 13); L 2 (C 12): <;>
L 30 (C 52-53): Input argument 'in' might be unused. If this is OK, consider replacing it by ~. (CAN FIX)
----FIX MESSAGE <Replace name by ~.>
----CHANGE MESSAGE L 30 (C 52); L 30 (C 53): <~>
При назначении структуре это также показывает цель нового поля fix
, которое @High Performance Mark отмечает в своем комментарии к @gnovice answer; он кажется равным 1, когда имеется исправление, 2, когда сообщение является FIX MESSAGE
выше, и 4, когда сообщение является CHANGE MESSAGE
.
Вот быстрая и грязная функция Matlab, которая возвращает "фиксированную" строку, учитывая путь к m файлу. Нет проверки ошибок и т.д., И он не сохраняет файл обратно, поскольку я не обещаю, что он сработает. Вы также можете использовать общедоступный (!) API matlab.desktop.editor
для получения активного документа (getActive
) и использовать getter и setter в свойстве Text
, чтобы изменить документ на месте, не сохраняя его.
function str = applyAutoFixes(filepath)
msgs = checkcode(filepath,'-fix');
fid = fopen(filepath,'rt');
iiLine = 1;
lines = cell(0);
line = fgets(fid);
while ischar(line)
lines{iiLine} = line;
iiLine = iiLine+1;
line = fgets(fid);
end
fclose(fid);
pos = [0 cumsum(cellfun('length',lines))];
str = [lines{:}];
fixes = msgs([msgs.fix] == 4);
%// Iterate backwards to try to prevent changing the indexing of 'str'
%// Note that two changes could still conflict with eachother. You could check
%// for this, or iteratively run mlint and fix one problem at a time.
for fix = fliplr(fixes(:)')
%'// fix.column is a 2x2 - not sure what the second column is used for
change_start = pos(fix.line(1)) + fix.column(1,1);
change_end = pos(fix.line(2)) + fix.column(2,1);
if change_start >= change_end
%// Seems to be an insertion
str = [str(1:change_start) fix.message str(change_start+1:end)];
else
%// Seems to be a replacement
str = [str(1:change_start-1) fix.message str(change_end+1:end)];
end
end
Ответ 3
Я знаю, что это старый пост, но я просто нуждался в этом недавно и немного улучшил исходный код, поэтому, если кто-то еще нуждается в нем, он есть. Он ищет недостающие ";" в функциях, а не только в обычных скриптах, поддерживает пробелы в коде и записывает только файлы, которые что-то изменили.
function [] = add_semicolon(fileName)
%# Find the lines where a given mlint warning occurs:
mlintIDinScript = 'NOPTS'; %# The ID of the warning
mlintIDinFunction = 'NOPRT';
mlintData = mlint(fileName,'-id'); %# Run mlint on the file
index = strcmp({mlintData.id},mlintIDinScript) | strcmp({mlintData.id},mlintIDinFunction); %# Find occurrences of the warnings...
lineNumbers = [mlintData(index).line]; %# ... and their line numbers
if isempty(lineNumbers)
return;
end;
%# Read the lines of code from the file:
fid = fopen(fileName,'rt');
%linesOfCode = textscan(fid,'%s', 'Whitespace', '\n\r'); %# Read each line
lineNo = 0;
tline = fgetl(fid);
while ischar(tline)
lineNo = lineNo + 1;
linesOfCode{lineNo} = tline;
tline = fgetl(fid);
end
fclose(fid);
%# Modify the lines of code:
%linesOfCode = linesOfCode{1}; %# Remove the outer cell array encapsulation
linesOfCode(lineNumbers) = strcat(linesOfCode(lineNumbers),';'); %# Add ';'
%# Write the lines of code back to the file:
fim = fopen(fileName,'wt');
fprintf(fim,'%s\n',linesOfCode{1:end-1}); %# Write all but the last line
fprintf(fim,'%s',linesOfCode{end}); %# Write the last line
fclose(fim);