From 708afedeb4e2ab0c540bbb00279f52667564ea37 Mon Sep 17 00:00:00 2001 From: Shane Kilkelly Date: Wed, 30 Aug 2017 14:01:20 +0100 Subject: [PATCH 1/3] Refactor out common code in AutocompleteManager. (first pass) --- .../auto-complete/AutoCompleteManager.coffee | 48 ++++++------------- .../aceEditor/auto-complete/Helpers.coffee | 33 +++++++++++++ 2 files changed, 47 insertions(+), 34 deletions(-) create mode 100644 services/web/public/coffee/ide/editor/directives/aceEditor/auto-complete/Helpers.coffee diff --git a/services/web/public/coffee/ide/editor/directives/aceEditor/auto-complete/AutoCompleteManager.coffee b/services/web/public/coffee/ide/editor/directives/aceEditor/auto-complete/AutoCompleteManager.coffee index 55104341e8..65d5113088 100644 --- a/services/web/public/coffee/ide/editor/directives/aceEditor/auto-complete/AutoCompleteManager.coffee +++ b/services/web/public/coffee/ide/editor/directives/aceEditor/auto-complete/AutoCompleteManager.coffee @@ -1,21 +1,13 @@ define [ "ide/editor/directives/aceEditor/auto-complete/CommandManager" "ide/editor/directives/aceEditor/auto-complete/EnvironmentManager" + "ide/editor/directives/aceEditor/auto-complete/Helpers" "ace/ace" "ace/ext-language_tools" -], (CommandManager, EnvironmentManager) -> +], (CommandManager, EnvironmentManager, Helpers) -> Range = ace.require("ace/range").Range aceSnippetManager = ace.require('ace/snippets').snippetManager - getLastCommandFragment = (lineUpToCursor) -> - if m = lineUpToCursor.match(/(\\[^\\]+)$/) - return m[1] - else - return null - - getCommandNameFromFragment = (commandFragment) -> - commandFragment?.match(/\\(\w+)\{/)?[1] - class AutoCompleteManager constructor: (@$scope, @editor, @element, @labelsManager, @graphics, @preamble) -> @suggestionManager = new CommandManager() @@ -48,15 +40,11 @@ define [ Preamble = @preamble GraphicsCompleter = getCompletions: (editor, session, pos, prefix, callback) -> - upToCursorRange = new Range(pos.row, 0, pos.row, pos.column) - lineUpToCursor = editor.getSession().getTextRange(upToCursorRange) - commandFragment = getLastCommandFragment(lineUpToCursor) + context = Helpers.getContext(editor, pos) + {lineUpToCursor, commandFragment, lineBeyondCursor, needsClosingBrace} = context if commandFragment match = commandFragment.match(/^~?\\(includegraphics(?:\[.*])?){([^}]*, *)?(\w*)/) if match - beyondCursorRange = new Range(pos.row, pos.column, pos.row, 99999) - lineBeyondCursor = editor.getSession().getTextRange(beyondCursorRange) - needsClosingBrace = !lineBeyondCursor.match(/^[^{]*}/) commandName = match[1] currentArg = match[3] graphicsPaths = Preamble.getGraphicsPaths() @@ -78,15 +66,11 @@ define [ labelsManager = @labelsManager LabelsCompleter = getCompletions: (editor, session, pos, prefix, callback) -> - upToCursorRange = new Range(pos.row, 0, pos.row, pos.column) - lineUpToCursor = editor.getSession().getTextRange(upToCursorRange) - commandFragment = getLastCommandFragment(lineUpToCursor) + context = Helpers.getContext(editor, pos) + {lineUpToCursor, commandFragment, lineBeyondCursor, needsClosingBrace} = context if commandFragment refMatch = commandFragment.match(/^~?\\([a-z]*ref){([^}]*, *)?(\w*)/) if refMatch - beyondCursorRange = new Range(pos.row, pos.column, pos.row, 99999) - lineBeyondCursor = editor.getSession().getTextRange(beyondCursorRange) - needsClosingBrace = !lineBeyondCursor.match(/^[^{]*}/) commandName = refMatch[1] currentArg = refMatch[2] result = [] @@ -108,15 +92,13 @@ define [ references = @$scope.$root._references ReferencesCompleter = getCompletions: (editor, session, pos, prefix, callback) -> - upToCursorRange = new Range(pos.row, 0, pos.row, pos.column) - lineUpToCursor = editor.getSession().getTextRange(upToCursorRange) - commandFragment = getLastCommandFragment(lineUpToCursor) + context = Helpers.getContext(editor, pos) + {lineUpToCursor, commandFragment, lineBeyondCursor, needsClosingBrace} = context if commandFragment - citeMatch = commandFragment.match(/^~?\\([a-z]*cite[a-z]*(?:\[.*])?){([^}]*, *)?(\w*)/) + citeMatch = commandFragment.match( + /^~?\\([a-z]*cite[a-z]*(?:\[.*])?){([^}]*, *)?(\w*)/ + ) if citeMatch - beyondCursorRange = new Range(pos.row, pos.column, pos.row, 99999) - lineBeyondCursor = editor.getSession().getTextRange(beyondCursorRange) - needsClosingBrace = !lineBeyondCursor.match(/^[^{]*}/) commandName = citeMatch[1] previousArgs = citeMatch[2] currentArg = citeMatch[3] @@ -160,8 +142,8 @@ define [ onChange: (change) -> cursorPosition = @editor.getCursorPosition() end = change.end - range = new Range(end.row, 0, end.row, end.column) - lineUpToCursor = @editor.getSession().getTextRange(range) + context = Helpers.getContext(editor, end) + {lineUpToCursor, commandFragment, lineBeyondCursor, needsClosingBrace} = context if lineUpToCursor.match(/.*%.*/) return lastCharIsBackslash = lineUpToCursor.slice(-1) == "\\" @@ -170,8 +152,6 @@ define [ if lastTwoChars.match(/^\\[^a-z]$/) @editor?.completer?.detach?() return - commandFragment = getLastCommandFragment(lineUpToCursor) - commandName = getCommandNameFromFragment(commandFragment) if commandName in ['begin', 'end'] return # Check that this change was made by us, not a collaborator @@ -310,5 +290,5 @@ define [ currentLineOffset = i + 1 break currentLine = text.slice(currentLineOffset, pos) - fragment = getLastCommandFragment(currentLine) or "" + fragment = Helpers.getLastCommandFragment(currentLine) or "" return fragment diff --git a/services/web/public/coffee/ide/editor/directives/aceEditor/auto-complete/Helpers.coffee b/services/web/public/coffee/ide/editor/directives/aceEditor/auto-complete/Helpers.coffee new file mode 100644 index 0000000000..2744d1fa29 --- /dev/null +++ b/services/web/public/coffee/ide/editor/directives/aceEditor/auto-complete/Helpers.coffee @@ -0,0 +1,33 @@ +define [ + "ace/ace" + "ace/ext-language_tools" +], () -> + Range = ace.require("ace/range").Range + + Helpers = + getLastCommandFragment: (lineUpToCursor) -> + if m = lineUpToCursor.match(/(\\[^\\]+)$/) + return m[1] + else + return null + + getCommandNameFromFragment: (commandFragment) -> + commandFragment?.match(/\\(\w+)\{/)?[1] + + getContext: (editor, pos) -> + upToCursorRange = new Range(pos.row, 0, pos.row, pos.column) + lineUpToCursor = editor.getSession().getTextRange(upToCursorRange) + commandFragment = Helpers.getLastCommandFragment(lineUpToCursor) + commandName = Helpers.getCommandNameFromFragment(commandFragment) + beyondCursorRange = new Range(pos.row, pos.column, pos.row, 99999) + lineBeyondCursor = editor.getSession().getTextRange(beyondCursorRange) + needsClosingBrace = !lineBeyondCursor.match(/^[^{]*}/) + return { + lineUpToCursor, + commandFragment, + commandName, + lineBeyondCursor, + needsClosingBrace + } + + return Helpers From 8a612df0098a2c669b2f6b83e16b449c8c0a9a9e Mon Sep 17 00:00:00 2001 From: Shane Kilkelly Date: Thu, 31 Aug 2017 08:59:38 +0100 Subject: [PATCH 2/3] fix use of context helper in onChange --- .../aceEditor/auto-complete/AutoCompleteManager.coffee | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/services/web/public/coffee/ide/editor/directives/aceEditor/auto-complete/AutoCompleteManager.coffee b/services/web/public/coffee/ide/editor/directives/aceEditor/auto-complete/AutoCompleteManager.coffee index 65d5113088..e760264191 100644 --- a/services/web/public/coffee/ide/editor/directives/aceEditor/auto-complete/AutoCompleteManager.coffee +++ b/services/web/public/coffee/ide/editor/directives/aceEditor/auto-complete/AutoCompleteManager.coffee @@ -142,8 +142,8 @@ define [ onChange: (change) -> cursorPosition = @editor.getCursorPosition() end = change.end - context = Helpers.getContext(editor, end) - {lineUpToCursor, commandFragment, lineBeyondCursor, needsClosingBrace} = context + context = Helpers.getContext(@editor, end) + {lineUpToCursor, commandFragment, commandName, lineBeyondCursor, needsClosingBrace} = context if lineUpToCursor.match(/.*%.*/) return lastCharIsBackslash = lineUpToCursor.slice(-1) == "\\" From b2257db2c2ab67eeca9aba15b3397d412b503187 Mon Sep 17 00:00:00 2001 From: James Allen Date: Tue, 5 Sep 2017 19:26:13 +0200 Subject: [PATCH 3/3] Don't get confused by commands in arguments in autocomplete --- .../auto-complete/AutoCompleteManager.coffee | 8 ++++---- .../aceEditor/auto-complete/Helpers.coffee | 16 ++++++++++++++-- 2 files changed, 18 insertions(+), 6 deletions(-) diff --git a/services/web/public/coffee/ide/editor/directives/aceEditor/auto-complete/AutoCompleteManager.coffee b/services/web/public/coffee/ide/editor/directives/aceEditor/auto-complete/AutoCompleteManager.coffee index e760264191..24a524b4b6 100644 --- a/services/web/public/coffee/ide/editor/directives/aceEditor/auto-complete/AutoCompleteManager.coffee +++ b/services/web/public/coffee/ide/editor/directives/aceEditor/auto-complete/AutoCompleteManager.coffee @@ -213,10 +213,10 @@ define [ range.start.column, ) ) - # Delete back to last backslash, as appropriate - lastBackslashIndex = lineUpToCursor.lastIndexOf('\\') - if lastBackslashIndex != -1 - leftRange.start.column = lastBackslashIndex + # Delete back to command start, as appropriate + commandStartIndex = Helpers.getLastCommandFragmentIndex(lineUpToCursor) + if commandStartIndex != -1 + leftRange.start.column = commandStartIndex else leftRange.start.column -= completions.filterText.length editor.session.remove(leftRange) diff --git a/services/web/public/coffee/ide/editor/directives/aceEditor/auto-complete/Helpers.coffee b/services/web/public/coffee/ide/editor/directives/aceEditor/auto-complete/Helpers.coffee index 2744d1fa29..7beb41debd 100644 --- a/services/web/public/coffee/ide/editor/directives/aceEditor/auto-complete/Helpers.coffee +++ b/services/web/public/coffee/ide/editor/directives/aceEditor/auto-complete/Helpers.coffee @@ -6,11 +6,23 @@ define [ Helpers = getLastCommandFragment: (lineUpToCursor) -> - if m = lineUpToCursor.match(/(\\[^\\]+)$/) - return m[1] + if (index = Helpers.getLastCommandFragmentIndex(lineUpToCursor)) > -1 + return lineUpToCursor.slice(index) else return null + getLastCommandFragmentIndex: (lineUpToCursor) -> + # This is hack to let us skip over commands in arguments, and + # go to the command on the same 'level' as us. E.g. + # \includegraphics[width=\textwidth]{.. + # should not match the \textwidth. + blankArguments = lineUpToCursor.replace /\[([^\]]*)\]/g, (args) -> + Array(args.length+1).join('.') + if m = blankArguments.match(/(\\[^\\]+)$/) + return m.index + else + return -1 + getCommandNameFromFragment: (commandFragment) -> commandFragment?.match(/\\(\w+)\{/)?[1]