From 7ecadb14f6b7ca9d76edb586c510610ba393cec8 Mon Sep 17 00:00:00 2001 From: Shane Kilkelly Date: Mon, 3 Jul 2017 13:36:24 +0100 Subject: [PATCH 1/6] Add a skeleton of a custom insertMatch function --- .../auto-complete/AutoCompleteManager.coffee | 20 +++++++++++++++++++ 1 file changed, 20 insertions(+) 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 cbcdc2eac7..1488c7e4ed 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 @@ -5,6 +5,7 @@ define [ "ace/ext-language_tools" ], (SuggestionManager, SnippetManager) -> Range = ace.require("ace/range").Range + aceSnippetManager = ace.require('ace/snippets').snippetManager getLastCommandFragment = (lineUpToCursor) -> if m = lineUpToCursor.match(/(\\[^\\]+)$/) @@ -154,6 +155,25 @@ define [ if this.completions.filterText.match(/^\\begin\{/) and nextChar == "}" editor.session.remove(range) + if !data? + completions = this.completions + popup = editor.completer.popup + data = popup.getData(popup.getRow()) + data.completer = + insertMatch: (editor, matchData) -> + console.log ">> custom insertMatch" + console.log ">> data", data + ranges = editor.selection.getAllRanges() + for range in ranges + range.start.column -= completions.filterText.length; + editor.session.remove(range); + if matchData.snippet + console.log ">> snippet" + aceSnippetManager.insertSnippet(editor, matchData.snippet); + else + console.log ">> string", matchData + editor.execCommand("insertstring", matchData.value || matchData); + Autocomplete::_insertMatch.call this, data # Overwrite this to set autoInsert = false and set font size From 127d5ded86bf867a1b3bd43a0144e1319f6cf291 Mon Sep 17 00:00:00 2001 From: Shane Kilkelly Date: Mon, 3 Jul 2017 13:37:06 +0100 Subject: [PATCH 2/6] Remove erroneous log --- .../aceEditor/auto-complete/AutoCompleteManager.coffee | 1 - 1 file changed, 1 deletion(-) 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 1488c7e4ed..5606f3e6fa 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 @@ -162,7 +162,6 @@ define [ data.completer = insertMatch: (editor, matchData) -> console.log ">> custom insertMatch" - console.log ">> data", data ranges = editor.selection.getAllRanges() for range in ranges range.start.column -= completions.filterText.length; From 415de9e2ec491cff0a4d78c4e6ec32fe8efba38d Mon Sep 17 00:00:00 2001 From: Shane Kilkelly Date: Mon, 3 Jul 2017 15:12:15 +0100 Subject: [PATCH 3/6] Experimental handling of completion for existing commands --- .../auto-complete/AutoCompleteManager.coffee | 32 ++++++++++++++++--- 1 file changed, 27 insertions(+), 5 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 5606f3e6fa..60164782f7 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 @@ -161,16 +161,38 @@ define [ data = popup.getData(popup.getRow()) data.completer = insertMatch: (editor, matchData) -> - console.log ">> custom insertMatch" ranges = editor.selection.getAllRanges() for range in ranges - range.start.column -= completions.filterText.length; - editor.session.remove(range); + left = _.clone(range) + right = _.clone(range) + left.start.column -= completions.filterText.length; + editor.session.remove(left); + beyondCursorRange = new Range( + right.start.row, + right.start.column, + right.end.row, + 99999 + ) + lineBeyondCursor = editor.getSession().getTextRange(beyondCursorRange) + if lineBeyondCursor + if partialCommandMatch = lineBeyondCursor.match(/^([a-z0-9]+)\{/) + # We've got a partial command after the cursor + commandTail = partialCommandMatch[1] + # remove rest of the partial command + right.end.column += commandTail.length - completions.filterText.length + editor.session.remove(right); + # trim the completion text to just the command, without braces + # example: '\cite{}' -> '\cite' + if matchData.snippet + matchData.snippet = matchData.snippet.replace(/[{\[].*[}\]]/, '') + if matchData.caption + matchData.caption = matchData.caption.replace(/[{\[].*[}\]]/, '') + if matchData.value + matchData.value = matchData.value.replace(/[{\[].*[}\]]/, '') + # finally, insert the match if matchData.snippet - console.log ">> snippet" aceSnippetManager.insertSnippet(editor, matchData.snippet); else - console.log ">> string", matchData editor.execCommand("insertstring", matchData.value || matchData); Autocomplete::_insertMatch.call this, data From 96d269e348e7a08c2fbcd76eceb480c78f036dfe Mon Sep 17 00:00:00 2001 From: Shane Kilkelly Date: Mon, 3 Jul 2017 15:13:27 +0100 Subject: [PATCH 4/6] Use existential operator to check existence --- .../aceEditor/auto-complete/AutoCompleteManager.coffee | 6 +++--- 1 file changed, 3 insertions(+), 3 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 60164782f7..1669308762 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 @@ -183,11 +183,11 @@ define [ editor.session.remove(right); # trim the completion text to just the command, without braces # example: '\cite{}' -> '\cite' - if matchData.snippet + if matchData.snippet? matchData.snippet = matchData.snippet.replace(/[{\[].*[}\]]/, '') - if matchData.caption + if matchData.caption? matchData.caption = matchData.caption.replace(/[{\[].*[}\]]/, '') - if matchData.value + if matchData.value? matchData.value = matchData.value.replace(/[{\[].*[}\]]/, '') # finally, insert the match if matchData.snippet From 08faa64b57f28a7ec9ed2966247d957f743ec287 Mon Sep 17 00:00:00 2001 From: Shane Kilkelly Date: Mon, 3 Jul 2017 15:20:36 +0100 Subject: [PATCH 5/6] Add comment explaining the custom `insertMatch` --- .../aceEditor/auto-complete/AutoCompleteManager.coffee | 9 +++++++++ 1 file changed, 9 insertions(+) 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 1669308762..9115cdcf5f 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 @@ -155,6 +155,15 @@ define [ if this.completions.filterText.match(/^\\begin\{/) and nextChar == "}" editor.session.remove(range) + # Provide our own `insertMatch` implementation. + # See the `insertMatch` method of Autocomplete in `ext-language_tools.js`. + # We need this to account for editing existing commands, particularly when + # adding a prefix. + # We fix this by detecting when the cursor is in the middle of an existing + # command, and adjusting the insertions/deletions accordingly. + # Example: + # when changing `\ref{}` to `\href{}`, ace default behaviour + # is likely to end up with `\href{}ref{}` if !data? completions = this.completions popup = editor.completer.popup From 68c942582f2890dc133cc89daed4ba172d2d6559 Mon Sep 17 00:00:00 2001 From: Shane Kilkelly Date: Tue, 4 Jul 2017 08:48:45 +0100 Subject: [PATCH 6/6] Clean up the custom insertMatch function --- .../auto-complete/AutoCompleteManager.coffee | 33 ++++++++++--------- 1 file changed, 17 insertions(+), 16 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 9115cdcf5f..d269388e76 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 @@ -170,27 +170,28 @@ define [ data = popup.getData(popup.getRow()) data.completer = insertMatch: (editor, matchData) -> - ranges = editor.selection.getAllRanges() - for range in ranges - left = _.clone(range) - right = _.clone(range) - left.start.column -= completions.filterText.length; - editor.session.remove(left); - beyondCursorRange = new Range( - right.start.row, - right.start.column, - right.end.row, - 99999 + for range in editor.selection.getAllRanges() + leftRange = _.clone(range) + rightRange = _.clone(range) + # trim to left of cursor + leftRange.start.column -= completions.filterText.length; + editor.session.remove(leftRange); + lineBeyondCursor = editor.getSession().getTextRange( + new Range( + rightRange.start.row, + rightRange.start.column, + rightRange.end.row, + 99999 + ) ) - lineBeyondCursor = editor.getSession().getTextRange(beyondCursorRange) if lineBeyondCursor if partialCommandMatch = lineBeyondCursor.match(/^([a-z0-9]+)\{/) # We've got a partial command after the cursor commandTail = partialCommandMatch[1] - # remove rest of the partial command - right.end.column += commandTail.length - completions.filterText.length - editor.session.remove(right); - # trim the completion text to just the command, without braces + # remove rest of the partial command, right of cursor + rightRange.end.column += commandTail.length - completions.filterText.length + editor.session.remove(rightRange); + # trim the completion text to just the command, without braces or brackets # example: '\cite{}' -> '\cite' if matchData.snippet? matchData.snippet = matchData.snippet.replace(/[{\[].*[}\]]/, '')