Skip to content

Commit 6ec11eb

Browse files
committed
emacsdocomplete.m: improve matlab-shell tab completion for R2025a
This commit updates matlab-shell tab completion to complete filenames in R2025a and later.
1 parent 8686c85 commit 6ec11eb

File tree

1 file changed

+57
-42
lines changed

1 file changed

+57
-42
lines changed

toolbox/emacsdocomplete.m

Lines changed: 57 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -27,63 +27,71 @@ function emacsdocomplete(substring)
2727

2828
persistent verNum;
2929
if isempty(verNum)
30-
v = ver('MATLAB'); %#ok<*VERMATLAB>
30+
v = ver('MATLAB'); %#ok<*VERMATLAB>
3131
verNum = str2double(v.Version);
3232
end
3333

34+
qStr = strrep(substring, '''', '''''');
35+
lStr = num2str(length(substring));
36+
3437
if verNum >= 25 % R2025a and later
3538

36-
cmd = ['builtin(''_programmingAidsTest'', '''', ''', ...
37-
substring, ''', ', num2str(length(substring)), ', [])'];
38-
json = evalin('base', cmd);
39-
completionInfo = jsondecode(json);
39+
cmd = ['builtin(''_programmingAidsTest'', '''', ''', qStr, ''', ', lStr, ', [])'];
40+
cInfo = jsondecode(evalin('base', cmd)); % use base workspace for variable completions
41+
cMap = dictionary('', true);
42+
4043
disp(['Completions-Lisp:', newline, '''(']);
41-
if strcmp(completionInfo.widgetType, 'completion')
42-
useCellIndex = iscell(completionInfo.widgetData.choices);
43-
nChoices = length(completionInfo.widgetData.choices);
44-
for idx = 1 : nChoices
45-
if useCellIndex
46-
entry = completionInfo.widgetData.choices{idx};
47-
else
48-
entry = completionInfo.widgetData.choices(idx);
49-
end
50-
if isfield(entry, 'purpose')
51-
purpose = [entry.purpose, ' '];
52-
else
53-
purpose = '';
44+
if isfield(cInfo, "signatures")
45+
sigs = cInfo.signatures;
46+
cSigs = iscell(sigs);
47+
for i = 1 : length(sigs)
48+
if cSigs, args = sigs{i}.inputArguments; else, args = sigs(i).inputArguments; end
49+
cArgs = iscell(args);
50+
for j = 1 : length(args)
51+
if cArgs, arg = args{j}; else, arg = args(j); end
52+
if isfield(arg, 'widgetData') && isfield(arg.widgetData, 'choices')
53+
DispCompletionChoices(arg.widgetData.choices);
54+
end
5455
end
55-
desc = [purpose, '(' entry.matchType, ')'];
56-
desc = regexprep(desc,'"', '\\"');
57-
disp([' ("', entry.completion, '" . "', desc, '")']);
5856
end
57+
elseif isfield(cInfo, 'widgetData') && isfield(cInfo.widgetData, 'choices')
58+
DispCompletionChoices(cInfo.widgetData.choices);
5959
end
6060
disp(')');
6161

6262
else % R2024b and earlier
6363

6464
if verNum < 8.4
65-
% Pre R2014b: partial_string
66-
extracmd = '';
65+
extracmd = ''; % Pre R2014b: partial_string
6766
else
68-
% Post R2014b: partial_string, caret, num
69-
extracmd = [ ', ' num2str(length(substring)) ',0' ];
67+
extracmd = [', ', lStr, ', 0']; % Post R2014b: partial_string, caret, num
7068
end
69+
cmd = ['matlabMCRprocess_emacs = com.mathworks.jmi.MatlabMCR;' ...
70+
'emacs_completions_output = matlabMCRprocess_emacs.mtFindAllTabCompletions(''' ...
71+
qStr '''' extracmd '),' ...
72+
'clear(''matlabMCRprocess_emacs'',''emacs_completions_output'');'];
73+
evalin('base', cmd); % run in base to get completions on base workspace variables
7174

72-
substringQuoted = strrep(substring, '''', '''''');
73-
74-
command = ...
75-
['matlabMCRprocess_emacs = com.mathworks.jmi.MatlabMCR;' ...
76-
'emacs_completions_output = matlabMCRprocess_emacs.mtFindAllTabCompletions(''' ...
77-
substringQuoted '''' extracmd '),' ...
78-
'clear(''matlabMCRprocess_emacs'',''emacs_completions_output'');'];
79-
80-
% Completion engine needs to run in the base workspace to know what the variables you have
81-
% to work with are.
82-
evalin('base', command);
75+
end
8376

77+
function DispCompletionChoices(choices)
78+
nChoices = length(choices);
79+
cChoices = iscell(choices);
80+
for choiceIdx = 1 : nChoices
81+
if cChoices, entry = choices{choiceIdx}; else, entry = choices(choiceIdx); end
82+
if ~cMap.isKey(entry.completion)
83+
cMap(entry.completion) = true;
84+
if isfield(entry, 'purpose'), info = [entry.purpose, ' ']; else, info = ''; end
85+
desc = [info, '(' entry.matchType, ')'];
86+
desc = regexprep(desc, '"', '\\"');
87+
comp = regexprep(entry.completion, '"', '\\"');
88+
disp([' ("', comp, '" . "', desc, '")']);
89+
end
90+
end
8491
end
8592

86-
end
93+
end % emacsdocomplete
94+
8795

8896

8997
function done = UseDashComplete(substring)
@@ -106,11 +114,14 @@ function emacsdocomplete(substring)
106114
% 'sub3'
107115
%
108116
% See details in `matlab-shell-completion-list'.
117+
%
118+
% TODO: remove and use function signatures.
119+
% https://www.mathworks.com/help/mps/restfuljson/matlab-function-signatures-in-json.html
109120
%
110121

111122
persistent completeSw; % if completeSw(cmd), then supports -complete
112123
if isempty(completeSw)
113-
completeSw=containers.Map();
124+
completeSw = containers.Map(); % use containers.Map instead of dictionary for old releases
114125
end
115126

116127
done = false;
@@ -124,13 +135,13 @@ function emacsdocomplete(substring)
124135
else
125136
supportsDashComplete = false; % assume
126137
f = which(cmd);
127-
if regexp(f,'\.m$')
138+
if regexp(f, '\.m$')
128139
fid=fopen(f, 'r');
129140
if fid ~= -1
130141
while true
131142
l = fgetl(fid);
132143
if ~ischar(l), break, end
133-
if regexp(l,'SUPPORTS_DASH_COMPLETE')
144+
if regexp(l, 'SUPPORTS_DASH_COMPLETE')
134145
supportsDashComplete = true;
135146
break
136147
end
@@ -145,11 +156,15 @@ function emacsdocomplete(substring)
145156
% For /path/to/cmd.ext we have /path/to/cmd.complete which
146157
% signals that we can get the completions by calling
147158
% CMD -complete ARGS
148-
completeCmd = regexprep(substring,'^(\w+)','$1 -complete');
159+
completeCmd = regexprep(substring, '^(\w+)', '$1 -complete');
149160
disp('emacs_completions_output =');
150-
evalin('base',completeCmd);
161+
evalin('base', completeCmd);
151162
done = true;
152163
end
153164
end
154165

155166
end
167+
168+
% [EOF] toolbox/emacsdocomplete.m
169+
170+
% LocalWords: ciolfi ludlam zappo gmail Rprocess Sw

0 commit comments

Comments
 (0)