Nate Stemen пре 9 година
родитељ
комит
2f03bb6015

+ 17 - 16
services/web/public/coffee/ide/editor/directives/aceEditor.coffee

@@ -13,6 +13,7 @@ define [
 	"ide/labels/services/labels"
 	"ide/labels/services/labels"
 	"ide/graphics/services/graphics"
 	"ide/graphics/services/graphics"
 	"ide/preamble/services/preamble"
 	"ide/preamble/services/preamble"
+	"ide/files/services/files"
 ], (App, Ace, SearchBox, ModeList, UndoManager, AutoCompleteManager, SpellCheckManager, HighlightsManager, CursorPositionManager, TrackChangesManager, LabelsManager) ->
 ], (App, Ace, SearchBox, ModeList, UndoManager, AutoCompleteManager, SpellCheckManager, HighlightsManager, CursorPositionManager, TrackChangesManager, LabelsManager) ->
 	EditSession = ace.require('ace/edit_session').EditSession
 	EditSession = ace.require('ace/edit_session').EditSession
 	ModeList = ace.require('ace/ext/modelist')
 	ModeList = ace.require('ace/ext/modelist')
@@ -35,7 +36,7 @@ define [
 			url = ace.config._moduleUrl(args...) + "?fingerprint=#{window.aceFingerprint}"
 			url = ace.config._moduleUrl(args...) + "?fingerprint=#{window.aceFingerprint}"
 			return url
 			return url
 
 
-	App.directive "aceEditor", ($timeout, $compile, $rootScope, event_tracking, localStorage, $cacheFactory, labels, graphics, preamble, $http) ->
+	App.directive "aceEditor", ($timeout, $compile, $rootScope, event_tracking, localStorage, $cacheFactory, labels, graphics, preamble, files, $http) ->
 		monkeyPatchSearch($rootScope, $compile)
 		monkeyPatchSearch($rootScope, $compile)
 
 
 		return  {
 		return  {
@@ -103,7 +104,7 @@ define [
 				cursorPositionManager = new CursorPositionManager(scope, editor, element, localStorage)
 				cursorPositionManager = new CursorPositionManager(scope, editor, element, localStorage)
 				trackChangesManager   = new TrackChangesManager(scope, editor, element)
 				trackChangesManager   = new TrackChangesManager(scope, editor, element)
 				labelsManager = new LabelsManager(scope, editor, element, labels)
 				labelsManager = new LabelsManager(scope, editor, element, labels)
-				autoCompleteManager = new AutoCompleteManager(scope, editor, element, labelsManager, graphics, preamble)
+				autoCompleteManager = new AutoCompleteManager(scope, editor, element, labelsManager, graphics, preamble, files)
 
 
 
 
 				# Prevert Ctrl|Cmd-S from triggering save dialog
 				# Prevert Ctrl|Cmd-S from triggering save dialog
@@ -115,16 +116,16 @@ define [
 				editor.commands.removeCommand "transposeletters"
 				editor.commands.removeCommand "transposeletters"
 				editor.commands.removeCommand "showSettingsMenu"
 				editor.commands.removeCommand "showSettingsMenu"
 				editor.commands.removeCommand "foldall"
 				editor.commands.removeCommand "foldall"
-				
+
 				# For European keyboards, the / is above 7 so needs Shift pressing.
 				# For European keyboards, the / is above 7 so needs Shift pressing.
-				# This comes through as Command-Shift-/ on OS X, which is mapped to 
+				# This comes through as Command-Shift-/ on OS X, which is mapped to
 				# toggleBlockComment.
 				# toggleBlockComment.
 				# This doesn't do anything for LaTeX, so remap this to togglecomment to
 				# This doesn't do anything for LaTeX, so remap this to togglecomment to
 				# work for European keyboards as normal.
 				# work for European keyboards as normal.
 				# On Windows, the key combo comes as Ctrl-Shift-7.
 				# On Windows, the key combo comes as Ctrl-Shift-7.
 				editor.commands.removeCommand "toggleBlockComment"
 				editor.commands.removeCommand "toggleBlockComment"
 				editor.commands.removeCommand "togglecomment"
 				editor.commands.removeCommand "togglecomment"
-				
+
 				editor.commands.addCommand {
 				editor.commands.addCommand {
 					name: "togglecomment",
 					name: "togglecomment",
 					bindKey: { win: "Ctrl-/|Ctrl-Shift-7", mac: "Command-/|Command-Shift-/" },
 					bindKey: { win: "Ctrl-/|Ctrl-Shift-7", mac: "Command-/|Command-Shift-/" },
@@ -140,7 +141,7 @@ define [
 					exec: (editor) ->
 					exec: (editor) ->
 						ace.require("ace/ext/searchbox").Search(editor, true)
 						ace.require("ace/ext/searchbox").Search(editor, true)
 					readOnly: true
 					readOnly: true
-				
+
 				# Bold text on CMD+B
 				# Bold text on CMD+B
 				editor.commands.addCommand
 				editor.commands.addCommand
 					name: "bold",
 					name: "bold",
@@ -154,7 +155,7 @@ define [
 							text = editor.getCopyText()
 							text = editor.getCopyText()
 							editor.insert("\\textbf{" + text + "}")
 							editor.insert("\\textbf{" + text + "}")
 					readOnly: false
 					readOnly: false
-                    
+
 				# Italicise text on CMD+I
 				# Italicise text on CMD+I
 				editor.commands.addCommand
 				editor.commands.addCommand
 					name: "italics",
 					name: "italics",
@@ -171,7 +172,7 @@ define [
 
 
 				scope.$watch "onCtrlEnter", (callback) ->
 				scope.$watch "onCtrlEnter", (callback) ->
 					if callback?
 					if callback?
-						editor.commands.addCommand 
+						editor.commands.addCommand
 							name: "compile",
 							name: "compile",
 							bindKey: win: "Ctrl-Enter", mac: "Command-Enter"
 							bindKey: win: "Ctrl-Enter", mac: "Command-Enter"
 							exec: (editor) =>
 							exec: (editor) =>
@@ -180,7 +181,7 @@ define [
 
 
 				scope.$watch "onCtrlJ", (callback) ->
 				scope.$watch "onCtrlJ", (callback) ->
 					if callback?
 					if callback?
-						editor.commands.addCommand 
+						editor.commands.addCommand
 							name: "toggle-review-panel",
 							name: "toggle-review-panel",
 							bindKey: win: "Ctrl-J", mac: "Command-J"
 							bindKey: win: "Ctrl-J", mac: "Command-J"
 							exec: (editor) =>
 							exec: (editor) =>
@@ -189,7 +190,7 @@ define [
 
 
 				scope.$watch "onCtrlShiftC", (callback) ->
 				scope.$watch "onCtrlShiftC", (callback) ->
 					if callback?
 					if callback?
-						editor.commands.addCommand 
+						editor.commands.addCommand
 							name: "add-new-comment",
 							name: "add-new-comment",
 							bindKey: win: "Ctrl-Shift-C", mac: "Command-Shift-C"
 							bindKey: win: "Ctrl-Shift-C", mac: "Command-Shift-C"
 							exec: (editor) =>
 							exec: (editor) =>
@@ -198,7 +199,7 @@ define [
 
 
 				scope.$watch "onCtrlShiftA", (callback) ->
 				scope.$watch "onCtrlShiftA", (callback) ->
 					if callback?
 					if callback?
-						editor.commands.addCommand 
+						editor.commands.addCommand
 							name: "toggle-track-changes",
 							name: "toggle-track-changes",
 							bindKey: win: "Ctrl-Shift-A", mac: "Command-Shift-A"
 							bindKey: win: "Ctrl-Shift-A", mac: "Command-Shift-A"
 							exec: (editor) =>
 							exec: (editor) =>
@@ -302,7 +303,7 @@ define [
 					if updateCount == 100
 					if updateCount == 100
 						event_tracking.send 'editor-interaction', 'multi-doc-update'
 						event_tracking.send 'editor-interaction', 'multi-doc-update'
 					scope.$emit "#{scope.name}:change"
 					scope.$emit "#{scope.name}:change"
-				
+
 				onScroll = (scrollTop) ->
 				onScroll = (scrollTop) ->
 					return if !scope.eventsBridge?
 					return if !scope.eventsBridge?
 					height = editor.renderer.layerConfig.maxHeight
 					height = editor.renderer.layerConfig.maxHeight
@@ -311,7 +312,7 @@ define [
 				onScrollbarVisibilityChanged = (event, vRenderer) ->
 				onScrollbarVisibilityChanged = (event, vRenderer) ->
 					return if !scope.eventsBridge?
 					return if !scope.eventsBridge?
 					scope.eventsBridge.emit "aceScrollbarVisibilityChanged", vRenderer.scrollBarV.isVisible, vRenderer.scrollBarV.width
 					scope.eventsBridge.emit "aceScrollbarVisibilityChanged", vRenderer.scrollBarV.isVisible, vRenderer.scrollBarV.width
-					
+
 				if scope.eventsBridge?
 				if scope.eventsBridge?
 					editor.renderer.on "scrollbarVisibilityChanged", onScrollbarVisibilityChanged
 					editor.renderer.on "scrollbarVisibilityChanged", onScrollbarVisibilityChanged
 
 
@@ -401,14 +402,14 @@ define [
 
 
 					session = editor.getSession()
 					session = editor.getSession()
 					session.off "changeScrollTop"
 					session.off "changeScrollTop"
-					
+
 					doc = session.getDocument()
 					doc = session.getDocument()
 					doc.off "change", onChange
 					doc.off "change", onChange
-				
+
 				editor.renderer.on "changeCharacterSize", () ->
 				editor.renderer.on "changeCharacterSize", () ->
 					scope.$apply () ->
 					scope.$apply () ->
 						scope.rendererData.lineHeight = editor.renderer.lineHeight
 						scope.rendererData.lineHeight = editor.renderer.lineHeight
-				
+
 				scope.$watch "rendererData", (rendererData) ->
 				scope.$watch "rendererData", (rendererData) ->
 					if rendererData?
 					if rendererData?
 						rendererData.lineHeight = editor.renderer.lineHeight
 						rendererData.lineHeight = editor.renderer.lineHeight

+ 26 - 2
services/web/public/coffee/ide/editor/directives/aceEditor/auto-complete/AutoCompleteManager.coffee

@@ -9,7 +9,7 @@ define [
 	aceSnippetManager = ace.require('ace/snippets').snippetManager
 	aceSnippetManager = ace.require('ace/snippets').snippetManager
 
 
 	class AutoCompleteManager
 	class AutoCompleteManager
-		constructor: (@$scope, @editor, @element, @labelsManager, @graphics, @preamble) ->
+		constructor: (@$scope, @editor, @element, @labelsManager, @graphics, @preamble, @files) ->
 			@suggestionManager = new CommandManager()
 			@suggestionManager = new CommandManager()
 
 
 			@monkeyPatchAutocomplete()
 			@monkeyPatchAutocomplete()
@@ -38,6 +38,8 @@ define [
 
 
 			Graphics = @graphics
 			Graphics = @graphics
 			Preamble = @preamble
 			Preamble = @preamble
+			Files = @files
+
 			GraphicsCompleter =
 			GraphicsCompleter =
 				getCompletions: (editor, session, pos, prefix, callback) ->
 				getCompletions: (editor, session, pos, prefix, callback) ->
 					context = Helpers.getContext(editor, pos)
 					context = Helpers.getContext(editor, pos)
@@ -63,6 +65,27 @@ define [
 								}
 								}
 							callback null, result
 							callback null, result
 
 
+			FilesCompleter =
+				getCompletions: (editor, session, pos, prefix, callback) =>
+					context = Helpers.getContext(editor, pos)
+					{lineUpToCursor, commandFragment, lineBeyondCursor, needsClosingBrace} = context
+					if commandFragment
+						match = commandFragment.match(/^\\(input|include){(\w*)/)
+						if match
+							commandName = match[1]
+							currentArg = match[2]
+							result = []
+							for file in Files.getTeXFiles()
+								if file.id != @$scope.docId
+									path = file.path
+									result.push {
+										caption: "\\#{commandName}{#{path}#{if needsClosingBrace then '}' else ''}",
+										value: "\\#{commandName}{#{path}#{if needsClosingBrace then '}' else ''}",
+										meta: "file",
+										score: 50
+									}
+							callback null, result
+
 			labelsManager = @labelsManager
 			labelsManager = @labelsManager
 			LabelsCompleter =
 			LabelsCompleter =
 				getCompletions: (editor, session, pos, prefix, callback) ->
 				getCompletions: (editor, session, pos, prefix, callback) ->
@@ -130,7 +153,8 @@ define [
 				SnippetCompleter,
 				SnippetCompleter,
 				ReferencesCompleter,
 				ReferencesCompleter,
 				LabelsCompleter,
 				LabelsCompleter,
-				GraphicsCompleter
+				GraphicsCompleter,
+				FilesCompleter
 			]
 			]
 
 
 		disable: () ->
 		disable: () ->

+ 16 - 16
services/web/public/coffee/ide/file-tree/FileTreeManager.coffee

@@ -13,15 +13,15 @@ define [
 				@loadRootFolder()
 				@loadRootFolder()
 				@loadDeletedDocs()
 				@loadDeletedDocs()
 				@$scope.$emit "file-tree:initialized"
 				@$scope.$emit "file-tree:initialized"
-				
+
 			@$scope.$watch "rootFolder", (rootFolder) =>
 			@$scope.$watch "rootFolder", (rootFolder) =>
 				if rootFolder?
 				if rootFolder?
 					@recalculateDocList()
 					@recalculateDocList()
 
 
 			@_bindToSocketEvents()
 			@_bindToSocketEvents()
-			
+
 			@$scope.multiSelectedCount = 0
 			@$scope.multiSelectedCount = 0
-			
+
 			$(document).on "click", =>
 			$(document).on "click", =>
 				@clearMultiSelectedEntities()
 				@clearMultiSelectedEntities()
 				$scope.$digest()
 				$scope.$digest()
@@ -46,7 +46,7 @@ define [
 						type: "file"
 						type: "file"
 					}
 					}
 					@recalculateDocList()
 					@recalculateDocList()
-					
+
 			@ide.socket.on "reciveNewFolder", (parent_folder_id, folder) =>
 			@ide.socket.on "reciveNewFolder", (parent_folder_id, folder) =>
 				parent_folder = @findEntityById(parent_folder_id) or @$scope.rootFolder
 				parent_folder = @findEntityById(parent_folder_id) or @$scope.rootFolder
 				@$scope.$apply () =>
 				@$scope.$apply () =>
@@ -85,25 +85,25 @@ define [
 			@ide.fileTreeManager.forEachEntity (entity) ->
 			@ide.fileTreeManager.forEachEntity (entity) ->
 				entity.selected = false
 				entity.selected = false
 			entity.selected = true
 			entity.selected = true
-		
+
 		toggleMultiSelectEntity: (entity) ->
 		toggleMultiSelectEntity: (entity) ->
 			entity.multiSelected = !entity.multiSelected
 			entity.multiSelected = !entity.multiSelected
 			@$scope.multiSelectedCount = @multiSelectedCount()
 			@$scope.multiSelectedCount = @multiSelectedCount()
-		
+
 		multiSelectedCount: () ->
 		multiSelectedCount: () ->
 			count = 0
 			count = 0
 			@forEachEntity (entity) ->
 			@forEachEntity (entity) ->
 				if entity.multiSelected
 				if entity.multiSelected
 					count++
 					count++
 			return count
 			return count
-		
+
 		getMultiSelectedEntities: () ->
 		getMultiSelectedEntities: () ->
 			entities = []
 			entities = []
 			@forEachEntity (e) ->
 			@forEachEntity (e) ->
 				if e.multiSelected
 				if e.multiSelected
 					entities.push e
 					entities.push e
 			return entities
 			return entities
-		
+
 		getMultiSelectedEntityChildNodes: () ->
 		getMultiSelectedEntityChildNodes: () ->
 			entities = @getMultiSelectedEntities()
 			entities = @getMultiSelectedEntities()
 			paths = {}
 			paths = {}
@@ -125,13 +125,13 @@ define [
 				if !prefixes[path]?
 				if !prefixes[path]?
 					child_entities.push entity
 					child_entities.push entity
 			return child_entities
 			return child_entities
-		
+
 		clearMultiSelectedEntities: () ->
 		clearMultiSelectedEntities: () ->
 			return if @$scope.multiSelectedCount == 0 # Be efficient, this is called a lot on 'click'
 			return if @$scope.multiSelectedCount == 0 # Be efficient, this is called a lot on 'click'
 			@forEachEntity (entity) ->
 			@forEachEntity (entity) ->
 				entity.multiSelected = false
 				entity.multiSelected = false
 			@$scope.multiSelectedCount = 0
 			@$scope.multiSelectedCount = 0
-		
+
 		multiSelectSelectedEntity: () ->
 		multiSelectSelectedEntity: () ->
 			@findSelectedEntity()?.multiSelected = true
 			@findSelectedEntity()?.multiSelected = true
 
 
@@ -140,7 +140,7 @@ define [
 			return false if !folder?
 			return false if !folder?
 			entity = @_findEntityByPathInFolder(folder, name)
 			entity = @_findEntityByPathInFolder(folder, name)
 			return entity?
 			return entity?
-			
+
 		findSelectedEntity: () ->
 		findSelectedEntity: () ->
 			selected = null
 			selected = null
 			@forEachEntity (entity) ->
 			@forEachEntity (entity) ->
@@ -178,7 +178,7 @@ define [
 			parts = path.split("/")
 			parts = path.split("/")
 			name = parts.shift()
 			name = parts.shift()
 			rest = parts.join("/")
 			rest = parts.join("/")
-			
+
 			if name == "."
 			if name == "."
 				return @_findEntityByPathInFolder(folder, rest)
 				return @_findEntityByPathInFolder(folder, rest)
 
 
@@ -268,7 +268,7 @@ define [
 					type: "doc"
 					type: "doc"
 					deleted: true
 					deleted: true
 				}
 				}
-				
+
 		recalculateDocList: () ->
 		recalculateDocList: () ->
 			@$scope.docs = []
 			@$scope.docs = []
 			@forEachEntity (entity, parentFolder, path) =>
 			@forEachEntity (entity, parentFolder, path) =>
@@ -287,7 +287,7 @@ define [
 					return -1
 					return -1
 				else
 				else
 					return 1
 					return 1
-			
+
 		getEntityPath: (entity) ->
 		getEntityPath: (entity) ->
 			@_getEntityPathInFolder @$scope.rootFolder, entity
 			@_getEntityPathInFolder @$scope.rootFolder, entity
 
 
@@ -349,7 +349,7 @@ define [
 			}
 			}
 
 
 		deleteEntity: (entity, callback = (error) ->) ->
 		deleteEntity: (entity, callback = (error) ->) ->
-			# We'll wait for the socket.io notification to 
+			# We'll wait for the socket.io notification to
 			# delete from scope.
 			# delete from scope.
 			return @ide.queuedHttp {
 			return @ide.queuedHttp {
 				method: "DELETE"
 				method: "DELETE"
@@ -367,7 +367,7 @@ define [
 				folder_id: parent_folder.id
 				folder_id: parent_folder.id
 				_csrf: window.csrfToken
 				_csrf: window.csrfToken
 			}
 			}
-			
+
 		_isChildFolder: (parent_folder, child_folder) ->
 		_isChildFolder: (parent_folder, child_folder) ->
 			parent_path = @getEntityPath(parent_folder) or "" # null if root folder
 			parent_path = @getEntityPath(parent_folder) or "" # null if root folder
 			child_path = @getEntityPath(child_folder) or "" # null if root folder
 			child_path = @getEntityPath(child_folder) or "" # null if root folder

+ 17 - 0
services/web/public/coffee/ide/files/services/files.coffee

@@ -0,0 +1,17 @@
+define [
+	"base"
+], (App) ->
+
+	App.factory 'files', (ide) ->
+
+		Files =
+			getTeXFiles: () ->
+				texFiles = []
+				ide.fileTreeManager.forEachEntity (entity, folder, path) ->
+					if entity.type == 'doc' && entity?.name?.match?(/.*\.(tex|sty|cls|dtx|ltx|def)/)
+						cloned = _.clone(entity)
+						cloned.path = path
+						texFiles.push cloned
+				return texFiles
+
+		return Files