function fHandle=TextTools(MacroName)
% TextTools - Collection of small macros for text manipulation
%
% Syntax:
% tt = TextTools;
% ttMacro = TextTools(MacroName)
%
% Description:
% TextTools provides a small collection of macros for text manipulation. It
% is intended to be used together with EditorMacro
% http://www.mathworks.com/matlabcentral/fileexchange/24615.
%
% Optional input argument MACRONAME selects one of the macros. Without
% input arguments ?funtion returns a struct containing function handles to
% all available macros.
%
% Included macros are:
% transpose_chars - Swap characters around the caret
% transpose_words - Swap words around the caret
% capitalize - Capitalize word starting from caret location
% fill_comment - Wrap current comment paragraph. Opposite to Matlab
% Editors wrap menu action no selection is needed.
%
%
% Examples:
% tt = TextTools;
% EditorMacro('Alt-Q',tt.fill_comment,'run')
%
%
% Warning:
% This code heavily relies on undocumented and unsupported Matlab
% functionality. Use at your own risk!
%
%
% Known issues (TODO):
% - There are some edge cases where fill_comment doesn't work properly.
% - fill_document produces two undo-steps.
%
%
% Bugs and suggestions:
% Please send to Perttu Ranta-aho (rantaaho at gmail dot com)
% Perttu Ranta-aho, <rantaaho (at) gmail dot com>
% $Revision: 1.1 $ $Date: 2009/08/24 21:36:06 $
error(nargchk(0, 1, nargin, 'struct'))
fHandles = struct(...
'transpose_chars',@transpose_chars,...
'transpose_words',@transpose_words,...
'fill_comment',@fill_comment, ...
'capitalize',@capitalize ...
);
if nargin
try
fHandle=fHandles(MacroName);
catch %#ok<CTCH>
error('PRa:TextTools:InvalidArg','Invalid MacroName.')
end
else
fHandle = fHandles;
end
function capitalize(hDocument,eventData) %#ok<INUSD>
% Capitalize from current position
caret = hDocument.getCaretPosition;
wordEnd = hDocument.getWordEndFromPos(caret);
hDocument.select(caret,wordEnd)
txt = char(hDocument.getSelectedText);
newTxt = [upper(txt(1)),lower(txt(2:end))];
hDocument.replaceSelection(newTxt);
end % capitalize
function fill_comment(hDocument,eventData) %#ok<INUSD>
% Wrap current comment paragraph.
commentWidth = com.mathworks.services.Prefs.getIntegerPref('EditorMaxCommentWidth');
if commentWidth == 0,
commentWidth = 75;
end
caretLine = hDocument.getLineStart(l_getCaretLine(hDocument));
txt = char(hDocument.getTextStartEnd(0,caretLine));
paraPat = {'^\s*([^% ]|%%|%\s*$)','lineanchors','dotexceptnewline'};
m = regexp(txt,paraPat{:});
startInd = hDocument.getLineEndFromPos(m(end)+1)+1;
txt = char(hDocument.getTextStartEnd(caretLine,hDocument.getLength));
m = regexp(txt,paraPat{:});
endInd = caretLine+m(1)-1;
para = char(hDocument.getTextStartEnd(startInd,endInd));
outerIndent = find(para=='%',1)-1;
innerIndent = max(find(para(outerIndent+2:end)~= ' ',1)-1,1);
para = regexprep(para,'^\s*\%\s?','','lineanchors');
para = strtrim(regexprep(para,'\s+',' ','lineanchors'));
newTxt = textwrap({para},commentWidth-outerIndent-innerIndent);
newTxt = strcat(...
repmat({['%',repmat(' ',1,innerIndent)]},size(newTxt,1),1), ...
newTxt,...
repmat({sprintf('\n')},size(newTxt,1),1));
newTxt = cat(2,newTxt{:});
try
hDocument.select(startInd,endInd);
awtinvoke(hDocument.java, 'replaceSelection', newTxt);
hDocument.select(startInd,startInd+numel(newTxt));
% hDocument.startBlockEdit; % Store only one undo-able action, doesn't work :(
% l_builtinAction(hDocument,'comment')
l_builtinAction(hDocument,'format') % Proper indent
% hDocument.endBlockEdit,
catch ME %#ok<NASGU>
%disp(ME.message)
end
end % fill_comment
function l_builtinAction(jHandle,actionID)
% Call built-in action
import java.awt.event.ActionEvent;
action = jHandle.getActionMap.get(actionID);
actionEvent = ActionEvent(jHandle, ActionEvent.ACTION_PERFORMED, actionID);
awtinvoke(action,'actionPerformed(Ljava.awt.event.ActionEvent;)',actionEvent,'');
end % l_builtinAction
function line = l_getCaretLine(hDocument)
% Return current line number
pos = hDocument.getCaretPosition;
line = hDocument.getLineFromPos(pos);
end % l_getCaretLine
function transpose_chars(hDocument,eventData) %#ok<INUSD>
% Transpose characters, similar to Emacs transpose-chars
caret = hDocument.getCaretPosition;
lngth = hDocument.getLength;
if caret == 0 || caret == lngth,
% caret is before the first character in the first line
% or after the last character in the document
return
end
pair = char(hDocument.getTextStartEnd(caret - 1, caret+1));
hDocument.select(caret-1, caret+1);
awtinvoke(hDocument.java, 'replaceSelection',fliplr(pair))
end % transpose_chars
function transpose_words(hDocument,eventData) %#ok<INUSD>
% Transpose words, similar to Emacs transpose-words
% Multiline version
chunkSize = 100;
offset = hDocument.getCaretPosition;
chunkStart = max(0,offset-chunkSize);
textChunk = char(hDocument.getTextStartEnd(chunkStart,...
min(offset+chunkSize,hDocument.getLength)));
[words, wordStart, wordEnd] = regexp(textChunk,'\w+',...
'match','start','end');
% Find the word on the left side
lWordInd = find((wordStart-(offset-chunkStart)-1)<0,1,'last');
if isempty(lWordInd),
lWordInd = 1;
elseif lWordInd == numel(words)
% Last word, do nothing.
return
end
% next word is the right side one
rWordInd = lWordInd + 1;
% Characters between two words
sep = textChunk(wordEnd(lWordInd)+1:wordStart(rWordInd)-1);
% Convert local indeces to global
wordStart = wordStart + chunkStart - 1;
wordEnd = wordEnd + chunkStart;
% Do replacing in one operation to have only one "undo" step.
hDocument.select(wordStart(lWordInd),wordEnd(rWordInd));
awtinvoke(hDocument.java, 'replaceSelection',...
[words{rWordInd},sep,words{lWordInd}]);
end % transpose_words
end % TextTools