From eaf9ae5b948767db3f10d3e4ccc08d8b4abd17cb Mon Sep 17 00:00:00 2001 From: Shane Kilkelly Date: Thu, 27 Jul 2017 11:57:01 +0100 Subject: [PATCH 1/7] Begin work on autocomplete for `includegraphics` --- .../ide/editor/directives/aceEditor.coffee | 6 +-- .../auto-complete/AutoCompleteManager.coffee | 40 ++++++++++++++++++- .../ide/file-tree/FileTreeManager.coffee | 2 + .../ide/graphics/services/graphics.coffee | 16 ++++++++ .../ide/preamble/services/preamble.coffee | 12 ++++++ 5 files changed, 71 insertions(+), 5 deletions(-) create mode 100644 services/web/public/coffee/ide/graphics/services/graphics.coffee create mode 100644 services/web/public/coffee/ide/preamble/services/preamble.coffee diff --git a/services/web/public/coffee/ide/editor/directives/aceEditor.coffee b/services/web/public/coffee/ide/editor/directives/aceEditor.coffee index af633ea369..990678ddc4 100644 --- a/services/web/public/coffee/ide/editor/directives/aceEditor.coffee +++ b/services/web/public/coffee/ide/editor/directives/aceEditor.coffee @@ -11,6 +11,7 @@ define [ "ide/editor/directives/aceEditor/track-changes/TrackChangesManager" "ide/editor/directives/aceEditor/labels/LabelsManager" "ide/labels/services/labels" + "ide/graphics/services/graphics" ], (App, Ace, SearchBox, ModeList, UndoManager, AutoCompleteManager, SpellCheckManager, HighlightsManager, CursorPositionManager, TrackChangesManager, LabelsManager) -> EditSession = ace.require('ace/edit_session').EditSession ModeList = ace.require('ace/ext/modelist') @@ -33,9 +34,8 @@ define [ url = ace.config._moduleUrl(args...) + "?fingerprint=#{window.aceFingerprint}" return url - App.directive "aceEditor", ($timeout, $compile, $rootScope, event_tracking, localStorage, $cacheFactory, labels) -> + App.directive "aceEditor", ($timeout, $compile, $rootScope, event_tracking, localStorage, $cacheFactory, labels, graphics) -> monkeyPatchSearch($rootScope, $compile) - return { scope: { @@ -102,7 +102,7 @@ define [ cursorPositionManager = new CursorPositionManager(scope, editor, element, localStorage) trackChangesManager = new TrackChangesManager(scope, editor, element) labelsManager = new LabelsManager(scope, editor, element, labels) - autoCompleteManager = new AutoCompleteManager(scope, editor, element, labelsManager) + autoCompleteManager = new AutoCompleteManager(scope, editor, element, labelsManager, graphics) # Prevert Ctrl|Cmd-S from triggering save dialog 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 c320266a5a..6259e893ab 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 @@ -17,7 +17,7 @@ define [ commandFragment?.match(/\\(\w+)\{/)?[1] class AutoCompleteManager - constructor: (@$scope, @editor, @element, @labelsManager) -> + constructor: (@$scope, @editor, @element, @labelsManager, @graphics) -> @suggestionManager = new SuggestionManager() @monkeyPatchAutocomplete() @@ -44,6 +44,36 @@ define [ SnippetCompleter = new SnippetManager() + Graphics = @graphics + 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) + 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] + result = [] + # result.push { + # caption: "\\#{commandName}{}", + # snippet: "\\#{commandName}{}", + # meta: "graphic", + # score: 60 + # } + for graphic in Graphics.getGraphicsFiles() + result.push { + caption: "\\#{commandName}{#{graphic.path}#{if needsClosingBrace then '}' else ''}", + value: "\\#{commandName}{#{graphic.path}#{if needsClosingBrace then '}' else ''}", + meta: "graphic", + score: 50 + } + callback null, result + labelsManager = @labelsManager LabelsCompleter = getCompletions: (editor, session, pos, prefix, callback) -> @@ -112,7 +142,13 @@ define [ else callback null, result - @editor.completers = [@suggestionManager, SnippetCompleter, ReferencesCompleter, LabelsCompleter] + @editor.completers = [ + @suggestionManager, + SnippetCompleter, + ReferencesCompleter, + LabelsCompleter, + GraphicsCompleter + ] disable: () -> @editor.setOptions({ diff --git a/services/web/public/coffee/ide/file-tree/FileTreeManager.coffee b/services/web/public/coffee/ide/file-tree/FileTreeManager.coffee index 0881e75cc8..f6b8a92710 100644 --- a/services/web/public/coffee/ide/file-tree/FileTreeManager.coffee +++ b/services/web/public/coffee/ide/file-tree/FileTreeManager.coffee @@ -202,6 +202,8 @@ define [ childPath = path + "/" + entity.name else childPath = entity.name + # FIXME: this is a hack + entity.path = childPath callback(entity, folder, childPath) if entity.children? @_forEachEntityInFolder(entity, childPath, callback) diff --git a/services/web/public/coffee/ide/graphics/services/graphics.coffee b/services/web/public/coffee/ide/graphics/services/graphics.coffee new file mode 100644 index 0000000000..6e0a03e849 --- /dev/null +++ b/services/web/public/coffee/ide/graphics/services/graphics.coffee @@ -0,0 +1,16 @@ +define [ + "base" +], (App) -> + + App.factory 'graphics', (ide) -> + + graphics = { + getGraphicsFiles: () -> + graphicsFiles = [] + ide.fileTreeManager.forEachEntity (f) -> + if f?.name?.match?(/.*\.(png|jpg|jpeg)/) + graphicsFiles.push f + return graphicsFiles + } + + return graphics diff --git a/services/web/public/coffee/ide/preamble/services/preamble.coffee b/services/web/public/coffee/ide/preamble/services/preamble.coffee new file mode 100644 index 0000000000..114f530d77 --- /dev/null +++ b/services/web/public/coffee/ide/preamble/services/preamble.coffee @@ -0,0 +1,12 @@ +define [ + "base" +], (App) -> + + App.factory 'preamble', (ide) -> + + Preamble = { + getPreambleText: () -> + + } + + return Preamble From a841646559b7d4495bec59e3c16442b6d8ffb2f9 Mon Sep 17 00:00:00 2001 From: Shane Kilkelly Date: Mon, 31 Jul 2017 11:28:21 +0100 Subject: [PATCH 2/7] Add preamble parser --- .../ide/preamble/preamble/services/preamble.coffee | 14 ++++++++++++++ 1 file changed, 14 insertions(+) create mode 100644 services/web/public/coffee/ide/preamble/preamble/services/preamble.coffee diff --git a/services/web/public/coffee/ide/preamble/preamble/services/preamble.coffee b/services/web/public/coffee/ide/preamble/preamble/services/preamble.coffee new file mode 100644 index 0000000000..bd52713952 --- /dev/null +++ b/services/web/public/coffee/ide/preamble/preamble/services/preamble.coffee @@ -0,0 +1,14 @@ +define [ + "base" +], (App) -> + + App.factory 'preamble', (ide) -> + + Preamble = { + getPreambleText: () -> + text = ide.editorManager.getCurrentDocValue().slice(0, 5000) + preamble = text.match(/([^]*)^\\begin\{document\}/m)[1] + + } + + return Preamble From eeabac76988815ed7d34e065f2f831df354aca83 Mon Sep 17 00:00:00 2001 From: Shane Kilkelly Date: Mon, 31 Jul 2017 11:28:52 +0100 Subject: [PATCH 3/7] Get graphics paths from preamble --- .../ide/editor/directives/aceEditor.coffee | 3 ++- .../ide/graphics/services/graphics.coffee | 5 ++--- .../ide/preamble/services/preamble.coffee | 18 +++++++++++++++--- 3 files changed, 19 insertions(+), 7 deletions(-) diff --git a/services/web/public/coffee/ide/editor/directives/aceEditor.coffee b/services/web/public/coffee/ide/editor/directives/aceEditor.coffee index 990678ddc4..19c34142c5 100644 --- a/services/web/public/coffee/ide/editor/directives/aceEditor.coffee +++ b/services/web/public/coffee/ide/editor/directives/aceEditor.coffee @@ -12,6 +12,7 @@ define [ "ide/editor/directives/aceEditor/labels/LabelsManager" "ide/labels/services/labels" "ide/graphics/services/graphics" + "ide/preamble/services/preamble" ], (App, Ace, SearchBox, ModeList, UndoManager, AutoCompleteManager, SpellCheckManager, HighlightsManager, CursorPositionManager, TrackChangesManager, LabelsManager) -> EditSession = ace.require('ace/edit_session').EditSession ModeList = ace.require('ace/ext/modelist') @@ -34,7 +35,7 @@ define [ url = ace.config._moduleUrl(args...) + "?fingerprint=#{window.aceFingerprint}" return url - App.directive "aceEditor", ($timeout, $compile, $rootScope, event_tracking, localStorage, $cacheFactory, labels, graphics) -> + App.directive "aceEditor", ($timeout, $compile, $rootScope, event_tracking, localStorage, $cacheFactory, labels, graphics, preamble) -> monkeyPatchSearch($rootScope, $compile) return { diff --git a/services/web/public/coffee/ide/graphics/services/graphics.coffee b/services/web/public/coffee/ide/graphics/services/graphics.coffee index 6e0a03e849..fdd4126b16 100644 --- a/services/web/public/coffee/ide/graphics/services/graphics.coffee +++ b/services/web/public/coffee/ide/graphics/services/graphics.coffee @@ -4,13 +4,12 @@ define [ App.factory 'graphics', (ide) -> - graphics = { + Graphics = getGraphicsFiles: () -> graphicsFiles = [] ide.fileTreeManager.forEachEntity (f) -> if f?.name?.match?(/.*\.(png|jpg|jpeg)/) graphicsFiles.push f return graphicsFiles - } - return graphics + return Graphics diff --git a/services/web/public/coffee/ide/preamble/services/preamble.coffee b/services/web/public/coffee/ide/preamble/services/preamble.coffee index 114f530d77..a8312ca4d7 100644 --- a/services/web/public/coffee/ide/preamble/services/preamble.coffee +++ b/services/web/public/coffee/ide/preamble/services/preamble.coffee @@ -4,9 +4,21 @@ define [ App.factory 'preamble', (ide) -> - Preamble = { + Preamble = getPreambleText: () -> - - } + text = ide.editorManager.getCurrentDocValue().slice(0, 5000) + preamble = text.match(/([^]*)^\\begin\{document\}/m)?[1] || "" + return preamble + + getGraphicsPaths: () -> + preamble = Preamble.getPreambleText() + graphicsPathsArgs = preamble.match(/\\graphicspath\{(.*)\}/)?[1] || "" + paths = [] + re = /\{([^}]*)\}/g + while match = re.exec(graphicsPathsArgs) + paths.push(match[1]) + return paths + + window.Preamble = Preamble return Preamble From f057f788e3270130678261e3bef34c5ca3d75c3e Mon Sep 17 00:00:00 2001 From: Shane Kilkelly Date: Mon, 31 Jul 2017 14:51:22 +0100 Subject: [PATCH 4/7] Autocomplete for graphics --- .../ide/editor/directives/aceEditor.coffee | 2 +- .../auto-complete/AutoCompleteManager.coffee | 19 ++++++++++--------- .../ide/file-tree/FileTreeManager.coffee | 2 -- .../ide/graphics/services/graphics.coffee | 8 +++++--- .../ide/preamble/services/preamble.coffee | 2 -- .../web/public/stylesheets/app/editor.less | 5 +++++ 6 files changed, 21 insertions(+), 17 deletions(-) diff --git a/services/web/public/coffee/ide/editor/directives/aceEditor.coffee b/services/web/public/coffee/ide/editor/directives/aceEditor.coffee index 19c34142c5..9b272841be 100644 --- a/services/web/public/coffee/ide/editor/directives/aceEditor.coffee +++ b/services/web/public/coffee/ide/editor/directives/aceEditor.coffee @@ -103,7 +103,7 @@ define [ cursorPositionManager = new CursorPositionManager(scope, editor, element, localStorage) trackChangesManager = new TrackChangesManager(scope, editor, element) labelsManager = new LabelsManager(scope, editor, element, labels) - autoCompleteManager = new AutoCompleteManager(scope, editor, element, labelsManager, graphics) + autoCompleteManager = new AutoCompleteManager(scope, editor, element, labelsManager, graphics, preamble) # Prevert Ctrl|Cmd-S from triggering save dialog 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 6259e893ab..7cc89c785a 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 @@ -17,7 +17,7 @@ define [ commandFragment?.match(/\\(\w+)\{/)?[1] class AutoCompleteManager - constructor: (@$scope, @editor, @element, @labelsManager, @graphics) -> + constructor: (@$scope, @editor, @element, @labelsManager, @graphics, @preamble) -> @suggestionManager = new SuggestionManager() @monkeyPatchAutocomplete() @@ -45,6 +45,7 @@ define [ SnippetCompleter = new SnippetManager() Graphics = @graphics + Preamble = @preamble GraphicsCompleter = getCompletions: (editor, session, pos, prefix, callback) -> upToCursorRange = new Range(pos.row, 0, pos.row, pos.column) @@ -58,17 +59,17 @@ define [ needsClosingBrace = !lineBeyondCursor.match(/^[^{]*}/) commandName = match[1] currentArg = match[3] + graphicsPaths = Preamble.getGraphicsPaths() result = [] - # result.push { - # caption: "\\#{commandName}{}", - # snippet: "\\#{commandName}{}", - # meta: "graphic", - # score: 60 - # } for graphic in Graphics.getGraphicsFiles() + path = graphic.path + for graphicsPath in graphicsPaths + if path.indexOf(graphicsPath) == 0 + path = path.slice(graphicsPath.length) + break result.push { - caption: "\\#{commandName}{#{graphic.path}#{if needsClosingBrace then '}' else ''}", - value: "\\#{commandName}{#{graphic.path}#{if needsClosingBrace then '}' else ''}", + caption: "\\#{commandName}{#{path}#{if needsClosingBrace then '}' else ''}", + value: "\\#{commandName}{#{path}#{if needsClosingBrace then '}' else ''}", meta: "graphic", score: 50 } diff --git a/services/web/public/coffee/ide/file-tree/FileTreeManager.coffee b/services/web/public/coffee/ide/file-tree/FileTreeManager.coffee index f6b8a92710..0881e75cc8 100644 --- a/services/web/public/coffee/ide/file-tree/FileTreeManager.coffee +++ b/services/web/public/coffee/ide/file-tree/FileTreeManager.coffee @@ -202,8 +202,6 @@ define [ childPath = path + "/" + entity.name else childPath = entity.name - # FIXME: this is a hack - entity.path = childPath callback(entity, folder, childPath) if entity.children? @_forEachEntityInFolder(entity, childPath, callback) diff --git a/services/web/public/coffee/ide/graphics/services/graphics.coffee b/services/web/public/coffee/ide/graphics/services/graphics.coffee index fdd4126b16..355614b7f4 100644 --- a/services/web/public/coffee/ide/graphics/services/graphics.coffee +++ b/services/web/public/coffee/ide/graphics/services/graphics.coffee @@ -7,9 +7,11 @@ define [ Graphics = getGraphicsFiles: () -> graphicsFiles = [] - ide.fileTreeManager.forEachEntity (f) -> - if f?.name?.match?(/.*\.(png|jpg|jpeg)/) - graphicsFiles.push f + ide.fileTreeManager.forEachEntity (entity, folder, path) -> + if entity.type == 'file' && entity?.name?.match?(/.*\.(png|jpg|jpeg|pdf|eps)/) + cloned = _.clone(entity) + cloned.path = path + graphicsFiles.push cloned return graphicsFiles return Graphics diff --git a/services/web/public/coffee/ide/preamble/services/preamble.coffee b/services/web/public/coffee/ide/preamble/services/preamble.coffee index a8312ca4d7..f95cfd9bbe 100644 --- a/services/web/public/coffee/ide/preamble/services/preamble.coffee +++ b/services/web/public/coffee/ide/preamble/services/preamble.coffee @@ -19,6 +19,4 @@ define [ paths.push(match[1]) return paths - window.Preamble = Preamble - return Preamble diff --git a/services/web/public/stylesheets/app/editor.less b/services/web/public/stylesheets/app/editor.less index 3c3aae945a..979bdd2bf6 100644 --- a/services/web/public/stylesheets/app/editor.less +++ b/services/web/public/stylesheets/app/editor.less @@ -504,3 +504,8 @@ height: auto; border-bottom: 1px solid @modal-header-border-color; } + +// Widen autocomplete popup +.ace_autocomplete { + width: 380px !important; +} From 9a85e42ddbdfc4dc3020c6b1e135b1776c4ade2f Mon Sep 17 00:00:00 2001 From: Shane Kilkelly Date: Tue, 1 Aug 2017 09:53:43 +0100 Subject: [PATCH 5/7] Remove stray file --- .../ide/preamble/preamble/services/preamble.coffee | 14 -------------- 1 file changed, 14 deletions(-) delete mode 100644 services/web/public/coffee/ide/preamble/preamble/services/preamble.coffee diff --git a/services/web/public/coffee/ide/preamble/preamble/services/preamble.coffee b/services/web/public/coffee/ide/preamble/preamble/services/preamble.coffee deleted file mode 100644 index bd52713952..0000000000 --- a/services/web/public/coffee/ide/preamble/preamble/services/preamble.coffee +++ /dev/null @@ -1,14 +0,0 @@ -define [ - "base" -], (App) -> - - App.factory 'preamble', (ide) -> - - Preamble = { - getPreambleText: () -> - text = ide.editorManager.getCurrentDocValue().slice(0, 5000) - preamble = text.match(/([^]*)^\\begin\{document\}/m)[1] - - } - - return Preamble From 3ffef7fe56d70038c2268bca63109d7f86521ff6 Mon Sep 17 00:00:00 2001 From: Shane Kilkelly Date: Tue, 1 Aug 2017 13:40:30 +0100 Subject: [PATCH 6/7] Dynamically adjust the width of autocomplete popup. --- .../auto-complete/AutoCompleteManager.coffee | 13 ++++++++++++- services/web/public/stylesheets/app/editor.less | 4 ---- 2 files changed, 12 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 7cc89c785a..348fe32f6b 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 @@ -282,7 +282,18 @@ define [ editor.completer.autoSelect = true editor.completer.showPopup(editor) editor.completer.cancelContextMenu() - $(editor.completer.popup?.container).css({'font-size': @$scope.fontSize + 'px'}) + container = $(editor.completer.popup?.container) + container.css({'font-size': @$scope.fontSize + 'px'}) + # Dynamically set width of autocomplete popup + if filtered = editor?.completer?.completions?.filtered + longestCaption = _.max(filtered.map( (c) -> c.caption.length )) + longestMeta = _.max(filtered.map( (c) -> c.meta.length )) + charScale = @$scope.fontSize * 0.7 + width = Math.min( + Math.round(longestCaption*charScale + longestMeta*charScale + 25), + 700 + ) + container.css({width: "#{width}px"}) if editor.completer?.completions?.filtered?.length == 0 editor.completer.detach() bindKey: "Ctrl-Space|Ctrl-Shift-Space|Alt-Space" diff --git a/services/web/public/stylesheets/app/editor.less b/services/web/public/stylesheets/app/editor.less index 979bdd2bf6..aae2ecdc9f 100644 --- a/services/web/public/stylesheets/app/editor.less +++ b/services/web/public/stylesheets/app/editor.less @@ -505,7 +505,3 @@ border-bottom: 1px solid @modal-header-border-color; } -// Widen autocomplete popup -.ace_autocomplete { - width: 380px !important; -} From 8a0f58c63d70fc42d155f7ff6e9a429accf46e34 Mon Sep 17 00:00:00 2001 From: Shane Kilkelly Date: Tue, 1 Aug 2017 14:28:10 +0100 Subject: [PATCH 7/7] Use correct character width --- .../auto-complete/AutoCompleteManager.coffee | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 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 348fe32f6b..751e534a32 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 @@ -288,10 +288,14 @@ define [ if filtered = editor?.completer?.completions?.filtered longestCaption = _.max(filtered.map( (c) -> c.caption.length )) longestMeta = _.max(filtered.map( (c) -> c.meta.length )) - charScale = @$scope.fontSize * 0.7 - width = Math.min( - Math.round(longestCaption*charScale + longestMeta*charScale + 25), - 700 + charWidth = editor.renderer.characterWidth + # between 280 and 700 px + width = Math.max( + Math.min( + Math.round(longestCaption*charWidth + longestMeta*charWidth + 5*charWidth), + 700 + ), + 280 ) container.css({width: "#{width}px"}) if editor.completer?.completions?.filtered?.length == 0