Просмотр исходного кода

Merge pull request #585 from sharelatex/sk-ac-refactor-autocompletemanager

Refactor out common code in AutocompleteManager.
James Allen 9 лет назад
Родитель
Сommit
fa13e1051a

+ 18 - 38
services/web/public/coffee/ide/editor/directives/aceEditor/auto-complete/AutoCompleteManager.coffee

@@ -1,21 +1,13 @@
 define [
 define [
 	"ide/editor/directives/aceEditor/auto-complete/CommandManager"
 	"ide/editor/directives/aceEditor/auto-complete/CommandManager"
 	"ide/editor/directives/aceEditor/auto-complete/EnvironmentManager"
 	"ide/editor/directives/aceEditor/auto-complete/EnvironmentManager"
+	"ide/editor/directives/aceEditor/auto-complete/Helpers"
 	"ace/ace"
 	"ace/ace"
 	"ace/ext-language_tools"
 	"ace/ext-language_tools"
-], (CommandManager, EnvironmentManager) ->
+], (CommandManager, EnvironmentManager, Helpers) ->
 	Range = ace.require("ace/range").Range
 	Range = ace.require("ace/range").Range
 	aceSnippetManager = ace.require('ace/snippets').snippetManager
 	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
 	class AutoCompleteManager
 		constructor: (@$scope, @editor, @element, @labelsManager, @graphics, @preamble) ->
 		constructor: (@$scope, @editor, @element, @labelsManager, @graphics, @preamble) ->
 			@suggestionManager = new CommandManager()
 			@suggestionManager = new CommandManager()
@@ -48,15 +40,11 @@ define [
 			Preamble = @preamble
 			Preamble = @preamble
 			GraphicsCompleter =
 			GraphicsCompleter =
 				getCompletions: (editor, session, pos, prefix, callback) ->
 				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
 					if commandFragment
 						match = commandFragment.match(/^~?\\(includegraphics(?:\[.*])?){([^}]*, *)?(\w*)/)
 						match = commandFragment.match(/^~?\\(includegraphics(?:\[.*])?){([^}]*, *)?(\w*)/)
 						if match
 						if match
-							beyondCursorRange = new Range(pos.row, pos.column, pos.row, 99999)
-							lineBeyondCursor = editor.getSession().getTextRange(beyondCursorRange)
-							needsClosingBrace = !lineBeyondCursor.match(/^[^{]*}/)
 							commandName = match[1]
 							commandName = match[1]
 							currentArg = match[3]
 							currentArg = match[3]
 							graphicsPaths = Preamble.getGraphicsPaths()
 							graphicsPaths = Preamble.getGraphicsPaths()
@@ -78,15 +66,11 @@ define [
 			labelsManager = @labelsManager
 			labelsManager = @labelsManager
 			LabelsCompleter =
 			LabelsCompleter =
 				getCompletions: (editor, session, pos, prefix, callback) ->
 				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
 					if commandFragment
 						refMatch = commandFragment.match(/^~?\\([a-z]*ref){([^}]*, *)?(\w*)/)
 						refMatch = commandFragment.match(/^~?\\([a-z]*ref){([^}]*, *)?(\w*)/)
 						if refMatch
 						if refMatch
-							beyondCursorRange = new Range(pos.row, pos.column, pos.row, 99999)
-							lineBeyondCursor = editor.getSession().getTextRange(beyondCursorRange)
-							needsClosingBrace = !lineBeyondCursor.match(/^[^{]*}/)
 							commandName = refMatch[1]
 							commandName = refMatch[1]
 							currentArg = refMatch[2]
 							currentArg = refMatch[2]
 							result = []
 							result = []
@@ -108,15 +92,13 @@ define [
 			references = @$scope.$root._references
 			references = @$scope.$root._references
 			ReferencesCompleter =
 			ReferencesCompleter =
 				getCompletions: (editor, session, pos, prefix, callback) ->
 				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
 					if commandFragment
-						citeMatch = commandFragment.match(/^~?\\([a-z]*cite[a-z]*(?:\[.*])?){([^}]*, *)?(\w*)/)
+						citeMatch = commandFragment.match(
+							/^~?\\([a-z]*cite[a-z]*(?:\[.*])?){([^}]*, *)?(\w*)/
+						)
 						if citeMatch
 						if citeMatch
-							beyondCursorRange = new Range(pos.row, pos.column, pos.row, 99999)
-							lineBeyondCursor = editor.getSession().getTextRange(beyondCursorRange)
-							needsClosingBrace = !lineBeyondCursor.match(/^[^{]*}/)
 							commandName = citeMatch[1]
 							commandName = citeMatch[1]
 							previousArgs = citeMatch[2]
 							previousArgs = citeMatch[2]
 							currentArg = citeMatch[3]
 							currentArg = citeMatch[3]
@@ -160,8 +142,8 @@ define [
 		onChange: (change) ->
 		onChange: (change) ->
 			cursorPosition = @editor.getCursorPosition()
 			cursorPosition = @editor.getCursorPosition()
 			end = change.end
 			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, commandName, lineBeyondCursor, needsClosingBrace} = context
 			if lineUpToCursor.match(/.*%.*/)
 			if lineUpToCursor.match(/.*%.*/)
 				return
 				return
 			lastCharIsBackslash = lineUpToCursor.slice(-1) == "\\"
 			lastCharIsBackslash = lineUpToCursor.slice(-1) == "\\"
@@ -170,8 +152,6 @@ define [
 			if lastTwoChars.match(/^\\[^a-z]$/)
 			if lastTwoChars.match(/^\\[^a-z]$/)
 				@editor?.completer?.detach?()
 				@editor?.completer?.detach?()
 				return
 				return
-			commandFragment = getLastCommandFragment(lineUpToCursor)
-			commandName = getCommandNameFromFragment(commandFragment)
 			if commandName in ['begin', 'end']
 			if commandName in ['begin', 'end']
 				return
 				return
 			# Check that this change was made by us, not a collaborator
 			# Check that this change was made by us, not a collaborator
@@ -233,10 +213,10 @@ define [
 											range.start.column,
 											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
 									else
 										leftRange.start.column -= completions.filterText.length
 										leftRange.start.column -= completions.filterText.length
 									editor.session.remove(leftRange)
 									editor.session.remove(leftRange)
@@ -310,5 +290,5 @@ define [
 						currentLineOffset = i + 1
 						currentLineOffset = i + 1
 						break
 						break
 				currentLine = text.slice(currentLineOffset, pos)
 				currentLine = text.slice(currentLineOffset, pos)
-				fragment = getLastCommandFragment(currentLine) or ""
+				fragment = Helpers.getLastCommandFragment(currentLine) or ""
 				return fragment
 				return fragment

+ 45 - 0
services/web/public/coffee/ide/editor/directives/aceEditor/auto-complete/Helpers.coffee

@@ -0,0 +1,45 @@
+define [
+	"ace/ace"
+	"ace/ext-language_tools"
+], () ->
+	Range = ace.require("ace/range").Range
+
+	Helpers =
+		getLastCommandFragment: (lineUpToCursor) ->
+			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]
+
+		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