@ -9,448 +9,448 @@ import { PluginViewWrapper } from '@remix-ui/helper'
const EventManager = require ( '../../lib/events' )
const EventManager = require ( '../../lib/events' )
const profile = {
const profile = {
displayName : 'Editor' ,
displayName : 'Editor' ,
name : 'editor' ,
name : 'editor' ,
description : 'service - editor' ,
description : 'service - editor' ,
version : packageJson . version ,
version : packageJson . version ,
methods : [ 'highlight' , 'discardHighlight' , 'clearAnnotations' , 'addLineText' , 'discardLineTexts' , 'addAnnotation' , 'gotoLine' , 'revealRange' , 'getCursorPosition' , 'open' , 'addModel' , 'addErrorMarker' , 'clearErrorMarkers' , 'getText' ] ,
methods : [ 'highlight' , 'discardHighlight' , 'clearAnnotations' , 'addLineText' , 'discardLineTexts' , 'addAnnotation' , 'gotoLine' , 'revealRange' , 'getCursorPosition' , 'open' , 'addModel' , 'addErrorMarker' , 'clearErrorMarkers' , 'getText' ] ,
}
}
class Editor extends Plugin {
class Editor extends Plugin {
constructor ( ) {
constructor ( ) {
super ( profile )
super ( profile )
this . _themes = {
this . _themes = {
light : 'light' ,
light : 'light' ,
dark : 'vs-dark' ,
dark : 'vs-dark' ,
remixDark : 'remix-dark'
remixDark : 'remix-dark'
}
}
this . registeredDecorations = { sourceAnnotationsPerFile : { } , markerPerFile : { } , lineTextPerFile : { } }
this . registeredDecorations = { sourceAnnotationsPerFile : { } , markerPerFile : { } , lineTextPerFile : { } }
this . currentDecorations = { sourceAnnotationsPerFile : { } , markerPerFile : { } , lineTextPerFile : { } }
this . currentDecorations = { sourceAnnotationsPerFile : { } , markerPerFile : { } , lineTextPerFile : { } }
// Init
// Init
this . event = new EventManager ( )
this . event = new EventManager ( )
this . sessions = { }
this . sessions = { }
this . readOnlySessions = { }
this . readOnlySessions = { }
this . previousInput = ''
this . previousInput = ''
this . saveTimeout = null
this . saveTimeout = null
this . emptySession = null
this . emptySession = null
this . modes = {
this . modes = {
sol : 'sol' ,
sol : 'sol' ,
yul : 'sol' ,
yul : 'sol' ,
mvir : 'move' ,
mvir : 'move' ,
js : 'javascript' ,
js : 'javascript' ,
py : 'python' ,
py : 'python' ,
vy : 'python' ,
vy : 'python' ,
zok : 'zokrates' ,
zok : 'zokrates' ,
lex : 'lexon' ,
lex : 'lexon' ,
txt : 'text' ,
txt : 'text' ,
json : 'json' ,
json : 'json' ,
abi : 'json' ,
abi : 'json' ,
rs : 'rust' ,
rs : 'rust' ,
cairo : 'cairo' ,
cairo : 'cairo' ,
ts : 'typescript' ,
ts : 'typescript' ,
move : 'move'
move : 'move'
}
}
this . activated = false
this . activated = false
this . events = {
this . events = {
onBreakPointAdded : ( file , line ) => this . triggerEvent ( 'breakpointAdded' , [ file , line ] ) ,
onBreakPointAdded : ( file , line ) => this . triggerEvent ( 'breakpointAdded' , [ file , line ] ) ,
onBreakPointCleared : ( file , line ) => this . triggerEvent ( 'breakpointCleared' , [ file , line ] ) ,
onBreakPointCleared : ( file , line ) => this . triggerEvent ( 'breakpointCleared' , [ file , line ] ) ,
onDidChangeContent : ( file ) => this . _onChange ( file ) ,
onDidChangeContent : ( file ) => this . _onChange ( file ) ,
onEditorMounted : ( ) => this . triggerEvent ( 'editorMounted' , [ ] )
onEditorMounted : ( ) => this . triggerEvent ( 'editorMounted' , [ ] )
}
}
// to be implemented by the react component
// to be implemented by the react component
this . api = { }
this . api = { }
this . dispatch = null
this . dispatch = null
this . ref = null
this . ref = null
}
}
setDispatch ( dispatch ) {
setDispatch ( dispatch ) {
this . dispatch = dispatch
this . dispatch = dispatch
}
}
updateComponent ( state ) {
updateComponent ( state ) {
return < EditorUI
return < EditorUI
editorAPI = { state . api }
editorAPI = { state . api }
themeType = { state . currentThemeType }
themeType = { state . currentThemeType }
currentFile = { state . currentFile }
currentFile = { state . currentFile }
events = { state . events }
events = { state . events }
plugin = { state . plugin }
plugin = { state . plugin }
/ >
/ >
}
}
render ( ) {
render ( ) {
return < div ref = { ( element ) => {
return < div ref = { ( element ) => {
this . ref = element
this . ref = element
this . ref . currentContent = ( ) => this . currentContent ( ) // used by e2e test
this . ref . currentContent = ( ) => this . currentContent ( ) // used by e2e test
this . ref . setCurrentContent = ( value ) => {
this . ref . setCurrentContent = ( value ) => {
if ( this . sessions [ this . currentFile ] ) {
if ( this . sessions [ this . currentFile ] ) {
this . sessions [ this . currentFile ] . setValue ( value )
this . sessions [ this . currentFile ] . setValue ( value )
this . _onChange ( this . currentFile )
this . _onChange ( this . currentFile )
}
}
this . ref . gotoLine = ( line , column ) => this . gotoLine ( line , column || 0 )
this . ref . getCursorPosition = ( ) => this . getCursorPosition ( )
this . ref . addDecoration = ( marker , filePath , typeOfDecoration ) => this . addDecoration ( marker , filePath , typeOfDecoration )
this . ref . clearDecorationsByPlugin = ( filePath , plugin , typeOfDecoration ) => this . clearDecorationsByPlugin ( filePath , plugin , typeOfDecoration )
this . ref . keepDecorationsFor = ( name , typeOfDecoration ) => this . keepDecorationsFor ( name , typeOfDecoration )
} } id = 'editorView' >
< PluginViewWrapper plugin = { this } / >
< / d i v >
}
renderComponent ( ) {
this . dispatch ( {
api : this . api ,
currentThemeType : this . currentThemeType ,
currentFile : this . currentFile ,
events : this . events ,
plugin : this
} )
}
triggerEvent ( name , params ) {
this . event . trigger ( name , params ) // internal stack
this . emit ( name , ... params ) // plugin stack
}
async onActivation ( ) {
this . activated = true
this . on ( 'sidePanel' , 'focusChanged' , ( name ) => {
this . keepDecorationsFor ( name , 'sourceAnnotationsPerFile' )
this . keepDecorationsFor ( name , 'markerPerFile' )
} )
this . on ( 'sidePanel' , 'pluginDisabled' , ( name ) => {
this . clearAllDecorationsFor ( name )
} )
this . on ( 'theme' , 'themeLoaded' , ( theme ) => {
this . currentThemeType = theme . quality
this . renderComponent ( )
} )
this . on ( 'fileManager' , 'noFileSelected' , async ( ) => {
this . currentFile = null
this . renderComponent ( )
} )
try {
this . currentThemeType = ( await this . call ( 'theme' , 'currentTheme' ) ) . quality
} catch ( e ) {
console . log ( 'unable to select the theme ' + e . message )
}
this . renderComponent ( )
}
onDeactivation ( ) {
this . off ( 'sidePanel' , 'focusChanged' )
this . off ( 'sidePanel' , 'pluginDisabled' )
}
async _onChange ( file ) {
this . triggerEvent ( 'didChangeFile' , [ file ] )
const currentFile = await this . call ( 'fileManager' , 'file' )
if ( ! currentFile ) {
return
}
if ( currentFile !== file ) {
return
}
const input = this . get ( currentFile )
if ( ! input ) {
return
}
// if there's no change, don't do anything
if ( input === this . previousInput ) {
return
}
this . previousInput = input
// fire storage update
// NOTE: save at most once per 5 seconds
if ( this . saveTimeout ) {
window . clearTimeout ( this . saveTimeout )
}
}
}
this . saveTimeout = window . setTimeout ( ( ) => {
this . ref . gotoLine = ( line , column ) => this . gotoLine ( line , column || 0 )
this . triggerEvent ( 'contentChanged' , [ ] )
this . ref . getCursorPosition = ( ) => this . getCursorPosition ( )
this . triggerEvent ( 'requiringToSaveCurrentfile' , [ ] )
this . ref . addDecoration = ( marker , filePath , typeOfDecoration ) => this . addDecoration ( marker , filePath , typeOfDecoration )
} , 500 )
this . ref . clearDecorationsByPlugin = ( filePath , plugin , typeOfDecoration ) => this . clearDecorationsByPlugin ( filePath , plugin , typeOfDecoration )
}
this . ref . keepDecorationsFor = ( name , typeOfDecoration ) => this . keepDecorationsFor ( name , typeOfDecoration )
} } id = 'editorView' >
_switchSession ( path ) {
< PluginViewWrapper plugin = { this } / >
if ( path === this . currentFile ) return
< / d i v >
this . triggerEvent ( 'sessionSwitched' , [ ] )
}
this . currentFile = path
this . renderComponent ( )
renderComponent ( ) {
}
this . dispatch ( {
api : this . api ,
/ * *
currentThemeType : this . currentThemeType ,
currentFile : this . currentFile ,
events : this . events ,
plugin : this
} )
}
triggerEvent ( name , params ) {
this . event . trigger ( name , params ) // internal stack
this . emit ( name , ... params ) // plugin stack
}
async onActivation ( ) {
this . activated = true
this . on ( 'sidePanel' , 'focusChanged' , ( name ) => {
this . keepDecorationsFor ( name , 'sourceAnnotationsPerFile' )
this . keepDecorationsFor ( name , 'markerPerFile' )
} )
this . on ( 'sidePanel' , 'pluginDisabled' , ( name ) => {
this . clearAllDecorationsFor ( name )
} )
this . on ( 'theme' , 'themeLoaded' , ( theme ) => {
this . currentThemeType = theme . quality
this . renderComponent ( )
} )
this . on ( 'fileManager' , 'noFileSelected' , async ( ) => {
this . currentFile = null
this . renderComponent ( )
} )
try {
this . currentThemeType = ( await this . call ( 'theme' , 'currentTheme' ) ) . quality
} catch ( e ) {
console . log ( 'unable to select the theme ' + e . message )
}
this . renderComponent ( )
}
onDeactivation ( ) {
this . off ( 'sidePanel' , 'focusChanged' )
this . off ( 'sidePanel' , 'pluginDisabled' )
}
async _onChange ( file ) {
this . triggerEvent ( 'didChangeFile' , [ file ] )
const currentFile = await this . call ( 'fileManager' , 'file' )
if ( ! currentFile ) {
return
}
if ( currentFile !== file ) {
return
}
const input = this . get ( currentFile )
if ( ! input ) {
return
}
// if there's no change, don't do anything
if ( input === this . previousInput ) {
return
}
this . previousInput = input
// fire storage update
// NOTE: save at most once per 5 seconds
if ( this . saveTimeout ) {
window . clearTimeout ( this . saveTimeout )
}
this . saveTimeout = window . setTimeout ( ( ) => {
this . triggerEvent ( 'contentChanged' , [ ] )
this . triggerEvent ( 'requiringToSaveCurrentfile' , [ ] )
} , 500 )
}
_switchSession ( path ) {
if ( path === this . currentFile ) return
this . triggerEvent ( 'sessionSwitched' , [ ] )
this . currentFile = path
this . renderComponent ( )
}
/ * *
* Get Ace mode base of the extension of the session file
* Get Ace mode base of the extension of the session file
* @ param { string } path Path of the file
* @ param { string } path Path of the file
* /
* /
_getMode ( path ) {
_getMode ( path ) {
if ( ! path ) return this . modes . txt
if ( ! path ) return this . modes . txt
const root = path . split ( '#' ) [ 0 ] . split ( '?' ) [ 0 ]
const root = path . split ( '#' ) [ 0 ] . split ( '?' ) [ 0 ]
let ext = root . indexOf ( '.' ) !== - 1 ? /[^.]+$/ . exec ( root ) : null
let ext = root . indexOf ( '.' ) !== - 1 ? /[^.]+$/ . exec ( root ) : null
if ( ext ) ext = ext [ 0 ]
if ( ext ) ext = ext [ 0 ]
else ext = 'txt'
else ext = 'txt'
return ext && this . modes [ ext ] ? this . modes [ ext ] : this . modes . txt
return ext && this . modes [ ext ] ? this . modes [ ext ] : this . modes . txt
}
}
async handleTypeScriptDependenciesOf ( path , content , readFile , exists ) {
async handleTypeScriptDependenciesOf ( path , content , readFile , exists ) {
if ( path . endsWith ( '.ts' ) ) {
if ( path . endsWith ( '.ts' ) ) {
// extract the import, resolve their content
// extract the import, resolve their content
// and add the imported files to Monaco through the `addModel`
// and add the imported files to Monaco through the `addModel`
// so Monaco can provide auto completion
// so Monaco can provide auto completion
const paths = path . split ( '/' )
const paths = path . split ( '/' )
paths . pop ( )
paths . pop ( )
const fromPath = paths . join ( '/' ) // get current execution context path
const fromPath = paths . join ( '/' ) // get current execution context path
for ( const match of content . matchAll ( /import\s+.*\s+from\s+(?:"(.*?)"|'(.*?)')/g ) ) {
for ( const match of content . matchAll ( /import\s+.*\s+from\s+(?:"(.*?)"|'(.*?)')/g ) ) {
let pathDep = match [ 2 ]
let pathDep = match [ 2 ]
if ( pathDep . startsWith ( './' ) || pathDep . startsWith ( '../' ) ) pathDep = resolve ( fromPath , pathDep )
if ( pathDep . startsWith ( './' ) || pathDep . startsWith ( '../' ) ) pathDep = resolve ( fromPath , pathDep )
if ( pathDep . startsWith ( '/' ) ) pathDep = pathDep . substring ( 1 )
if ( pathDep . startsWith ( '/' ) ) pathDep = pathDep . substring ( 1 )
if ( ! pathDep . endsWith ( '.ts' ) ) pathDep = pathDep + '.ts'
if ( ! pathDep . endsWith ( '.ts' ) ) pathDep = pathDep + '.ts'
try {
try {
// we can't use the fileManager plugin call directly
// we can't use the fileManager plugin call directly
// because it's itself called in a plugin context, and that causes a timeout in the plugin stack
// because it's itself called in a plugin context, and that causes a timeout in the plugin stack
const pathExists = await exists ( pathDep )
const pathExists = await exists ( pathDep )
let contentDep = ''
let contentDep = ''
if ( pathExists ) {
if ( pathExists ) {
contentDep = await readFile ( pathDep )
contentDep = await readFile ( pathDep )
if ( contentDep !== '' ) {
if ( contentDep !== '' ) {
this . emit ( 'addModel' , contentDep , 'typescript' , pathDep , this . readOnlySessions [ path ] )
this . emit ( 'addModel' , contentDep , 'typescript' , pathDep , this . readOnlySessions [ path ] )
}
} else {
console . log ( "The file " , pathDep , " can't be found." )
}
} catch ( e ) {
console . log ( e )
}
}
}
} else {
console . log ( "The file " , pathDep , " can't be found." )
}
} catch ( e ) {
console . log ( e )
}
}
}
}
}
}
/ * *
/ * *
* Create an editor session
* Create an editor session
* @ param { string } path path of the file
* @ param { string } path path of the file
* @ param { string } content Content of the file to open
* @ param { string } content Content of the file to open
* @ param { string } mode Mode for this file [ Default is ` text ` ]
* @ param { string } mode Mode for this file [ Default is ` text ` ]
* /
* /
async _createSession ( path , content , mode ) {
async _createSession ( path , content , mode ) {
if ( ! this . activated ) return
if ( ! this . activated ) return
this . emit ( 'addModel' , content , mode , path , this . readOnlySessions [ path ] )
this . emit ( 'addModel' , content , mode , path , this . readOnlySessions [ path ] )
return {
return {
path ,
path ,
language : mode ,
language : mode ,
setValue : ( content ) => {
setValue : ( content ) => {
this . emit ( 'setValue' , path , content )
this . emit ( 'setValue' , path , content )
} ,
} ,
getValue : ( ) => {
getValue : ( ) => {
return this . api . getValue ( path , content )
return this . api . getValue ( path , content )
} ,
} ,
dispose : ( ) => {
dispose : ( ) => {
this . emit ( 'disposeModel' , path )
this . emit ( 'disposeModel' , path )
}
}
}
}
}
}
/ * *
/ * *
* Attempts to find the string in the current document
* Attempts to find the string in the current document
* @ param { string } string
* @ param { string } string
* /
* /
find ( string ) {
find ( string ) {
return this . api . findMatches ( this . currentFile , string )
return this . api . findMatches ( this . currentFile , string )
}
}
addModel ( path , content ) {
addModel ( path , content ) {
this . emit ( 'addModel' , content , this . _getMode ( path ) , path , this . readOnlySessions [ path ] )
this . emit ( 'addModel' , content , this . _getMode ( path ) , path , this . readOnlySessions [ path ] )
}
}
/ * *
/ * *
* Display an Empty read - only session
* Display an Empty read - only session
* /
* /
displayEmptyReadOnlySession ( ) {
displayEmptyReadOnlySession ( ) {
if ( ! this . activated ) return
if ( ! this . activated ) return
this . currentFile = null
this . currentFile = null
this . emit ( 'addModel' , '' , 'text' , '_blank' , true )
this . emit ( 'addModel' , '' , 'text' , '_blank' , true )
}
}
/ * *
/ * *
* Set the text in the current session , if any .
* Set the text in the current session , if any .
* @ param { string } url Address of the text to replace .
* @ param { string } url Address of the text to replace .
* @ param { string } text New text to be place .
* @ param { string } text New text to be place .
* /
* /
setText ( url , text ) {
setText ( url , text ) {
if ( this . sessions [ url ] ) {
if ( this . sessions [ url ] ) {
this . sessions [ url ] . setValue ( text )
this . sessions [ url ] . setValue ( text )
}
}
}
}
/ * *
/ * *
* Get the text in the current session , if any .
* Get the text in the current session , if any .
* @ param { string } url Address of the content to retrieve .
* @ param { string } url Address of the content to retrieve .
* /
* /
getText ( url ) {
getText ( url ) {
if ( this . sessions [ url ] ) {
if ( this . sessions [ url ] ) {
return this . sessions [ url ] . getValue ( )
return this . sessions [ url ] . getValue ( )
}
}
}
}
/ * *
/ * *
* Upsert and open a session .
* Upsert and open a session .
* @ param { string } path Path of the session to open .
* @ param { string } path Path of the session to open .
* @ param { string } content Content of the document or update .
* @ param { string } content Content of the document or update .
* /
* /
async open ( path , content ) {
async open ( path , content ) {
/ *
/ *
we have the following cases :
we have the following cases :
- URL prepended with "localhost"
- URL prepended with "localhost"
- URL prepended with "browser"
- URL prepended with "browser"
- URL not prepended with the file explorer . We assume ( as it is in the whole app , that this is a "browser" URL
- URL not prepended with the file explorer . We assume ( as it is in the whole app , that this is a "browser" URL
* /
* /
if ( ! this . sessions [ path ] ) {
if ( ! this . sessions [ path ] ) {
this . readOnlySessions [ path ] = false
this . readOnlySessions [ path ] = false
const session = await this . _createSession ( path , content , this . _getMode ( path ) )
const session = await this . _createSession ( path , content , this . _getMode ( path ) )
this . sessions [ path ] = session
this . sessions [ path ] = session
} else if ( this . sessions [ path ] . getValue ( ) !== content ) {
} else if ( this . sessions [ path ] . getValue ( ) !== content ) {
this . sessions [ path ] . setValue ( content )
this . sessions [ path ] . setValue ( content )
}
this . _switchSession ( path )
}
}
this . _switchSession ( path )
}
/ * *
/ * *
* Upsert and Open a session and set it as Read - only .
* Upsert and Open a session and set it as Read - only .
* @ param { string } path Path of the session to open .
* @ param { string } path Path of the session to open .
* @ param { string } content Content of the document or update .
* @ param { string } content Content of the document or update .
* /
* /
async openReadOnly ( path , content ) {
async openReadOnly ( path , content ) {
if ( ! this . sessions [ path ] ) {
if ( ! this . sessions [ path ] ) {
this . readOnlySessions [ path ] = true
this . readOnlySessions [ path ] = true
const session = await this . _createSession ( path , content , this . _getMode ( path ) )
const session = await this . _createSession ( path , content , this . _getMode ( path ) )
this . sessions [ path ] = session
this . sessions [ path ] = session
}
this . _switchSession ( path )
}
}
this . _switchSession ( path )
}
/ * *
/ * *
* Content of the current session
* Content of the current session
* @ return { String } content of the file referenced by @ arg path
* @ return { String } content of the file referenced by @ arg path
* /
* /
currentContent ( ) {
currentContent ( ) {
return this . get ( this . current ( ) )
return this . get ( this . current ( ) )
}
}
/ * *
/ * *
* Content of the session targeted by @ arg path
* Content of the session targeted by @ arg path
* if @ arg path is null , the content of the current session is returned
* if @ arg path is null , the content of the current session is returned
* @ param { string } path Path of the session to get .
* @ param { string } path Path of the session to get .
* @ return { String } content of the file referenced by @ arg path
* @ return { String } content of the file referenced by @ arg path
* /
* /
get ( path ) {
get ( path ) {
if ( ! path || this . currentFile === path ) {
if ( ! path || this . currentFile === path ) {
return this . api . getValue ( path )
return this . api . getValue ( path )
} else if ( this . sessions [ path ] ) {
} else if ( this . sessions [ path ] ) {
return this . sessions [ path ] . getValue ( )
return this . sessions [ path ] . getValue ( )
}
}
}
}
/ * *
/ * *
* Path of the currently editing file
* Path of the currently editing file
* returns ` undefined ` if no session is being editer
* returns ` undefined ` if no session is being editer
* @ return { String } path of the current session
* @ return { String } path of the current session
* /
* /
current ( ) {
current ( ) {
return this . currentFile
return this . currentFile
}
}
/ * *
/ * *
* The position of the cursor
* The position of the cursor
* /
* /
getCursorPosition ( offset = true ) {
getCursorPosition ( offset = true ) {
return this . api . getCursorPosition ( offset )
return this . api . getCursorPosition ( offset )
}
}
/ * *
/ * *
* Remove the current session from the list of sessions .
* Remove the current session from the list of sessions .
* /
* /
discardCurrentSession ( ) {
discardCurrentSession ( ) {
if ( this . sessions [ this . currentFile ] ) {
if ( this . sessions [ this . currentFile ] ) {
delete this . sessions [ this . currentFile ]
delete this . sessions [ this . currentFile ]
this . currentFile = null
this . currentFile = null
}
}
}
}
/ * *
/ * *
* Remove a session based on its path .
* Remove a session based on its path .
* @ param { string } path
* @ param { string } path
* /
* /
discard ( path ) {
discard ( path ) {
if ( this . sessions [ path ] ) {
if ( this . sessions [ path ] ) {
this . sessions [ path ] . dispose ( )
this . sessions [ path ] . dispose ( )
delete this . sessions [ path ]
delete this . sessions [ path ]
}
if ( this . currentFile === path ) this . currentFile = null
}
}
if ( this . currentFile === path ) this . currentFile = null
}
/ * *
/ * *
* Increment the font size ( in pixels ) for the editor text .
* Increment the font size ( in pixels ) for the editor text .
* @ param { number } incr The amount of pixels to add to the font .
* @ param { number } incr The amount of pixels to add to the font .
* /
* /
editorFontSize ( incr ) {
editorFontSize ( incr ) {
if ( ! this . activated ) return
if ( ! this . activated ) return
const newSize = this . api . getFontSize ( ) + incr
const newSize = this . api . getFontSize ( ) + incr
if ( newSize >= 6 ) {
if ( newSize >= 6 ) {
this . emit ( 'setFontSize' , newSize )
this . emit ( 'setFontSize' , newSize )
}
}
}
}
/ * *
/ * *
* Resize the editor , and sets whether or not line wrapping is enabled .
* Resize the editor , and sets whether or not line wrapping is enabled .
* @ param { boolean } useWrapMode Enable ( or disable ) wrap mode
* @ param { boolean } useWrapMode Enable ( or disable ) wrap mode
* /
* /
resize ( useWrapMode ) {
resize ( useWrapMode ) {
if ( ! this . activated ) return
if ( ! this . activated ) return
this . emit ( 'setWordWrap' , useWrapMode )
this . emit ( 'setWordWrap' , useWrapMode )
}
}
/ * *
/ * *
* Moves the cursor and focus to the specified line and column number
* Moves the cursor and focus to the specified line and column number
* @ param { number } line
* @ param { number } line
* @ param { number } col
* @ param { number } col
* /
* /
gotoLine ( line , col ) {
gotoLine ( line , col ) {
if ( ! this . activated ) return
if ( ! this . activated ) return
this . emit ( 'focus' )
this . emit ( 'focus' )
this . emit ( 'revealLine' , line + 1 , col )
this . emit ( 'revealLine' , line + 1 , col )
}
}
/ * *
/ * *
* Reveals the range in the editor .
* Reveals the range in the editor .
* @ param { number } startLineNumber
* @ param { number } startLineNumber
* @ param { number } startColumn
* @ param { number } startColumn
* @ param { number } endLineNumber
* @ param { number } endLineNumber
* @ param { number } endColumn
* @ param { number } endColumn
* /
* /
revealRange ( startLineNumber , startColumn , endLineNumber , endColumn ) {
revealRange ( startLineNumber , startColumn , endLineNumber , endColumn ) {
if ( ! this . activated ) return
if ( ! this . activated ) return
this . emit ( 'focus' )
this . emit ( 'focus' )
console . log ( startLineNumber , startColumn , endLineNumber , endColumn )
console . log ( startLineNumber , startColumn , endLineNumber , endColumn )
this . emit ( 'revealRange' , startLineNumber , startColumn , endLineNumber , endColumn )
this . emit ( 'revealRange' , startLineNumber , startColumn , endLineNumber , endColumn )
}
}
/ * *
/ * *
* Scrolls to a line . If center is true , it puts the line in middle of screen ( or attempts to ) .
* Scrolls to a line . If center is true , it puts the line in middle of screen ( or attempts to ) .
* @ param { number } line The line to scroll to
* @ param { number } line The line to scroll to
* /
* /
scrollToLine ( line ) {
scrollToLine ( line ) {
if ( ! this . activated ) return
if ( ! this . activated ) return
this . emit ( 'revealLine' , line + 1 , 0 )
this . emit ( 'revealLine' , line + 1 , 0 )
}
}
/ * *
/ * *
* Clears all the decorations for the given @ arg filePath and @ arg plugin , if none is given , the current sesssion is used .
* Clears all the decorations for the given @ arg filePath and @ arg plugin , if none is given , the current sesssion is used .
* An annotation has the following shape :
* An annotation has the following shape :
column : - 1
column : - 1
@ -461,22 +461,22 @@ class Editor extends Plugin {
* @ param { String } plugin
* @ param { String } plugin
* @ param { String } typeOfDecoration
* @ param { String } typeOfDecoration
* /
* /
clearDecorationsByPlugin ( filePath , plugin , typeOfDecoration ) {
clearDecorationsByPlugin ( filePath , plugin , typeOfDecoration ) {
if ( filePath && ! this . sessions [ filePath ] ) throw new Error ( 'file not found' + filePath )
if ( filePath && ! this . sessions [ filePath ] ) throw new Error ( 'file not found' + filePath )
const path = filePath || this . currentFile
const path = filePath || this . currentFile
const { currentDecorations , registeredDecorations } = this . api . clearDecorationsByPlugin ( path , plugin , typeOfDecoration , this . registeredDecorations [ typeOfDecoration ] [ filePath ] || [ ] , this . currentDecorations [ typeOfDecoration ] [ filePath ] || [ ] )
const { currentDecorations , registeredDecorations } = this . api . clearDecorationsByPlugin ( path , plugin , typeOfDecoration , this . registeredDecorations [ typeOfDecoration ] [ filePath ] || [ ] , this . currentDecorations [ typeOfDecoration ] [ filePath ] || [ ] )
this . currentDecorations [ typeOfDecoration ] [ filePath ] = currentDecorations
this . currentDecorations [ typeOfDecoration ] [ filePath ] = currentDecorations
this . registeredDecorations [ typeOfDecoration ] [ filePath ] = registeredDecorations
this . registeredDecorations [ typeOfDecoration ] [ filePath ] = registeredDecorations
}
}
keepDecorationsFor ( plugin , typeOfDecoration ) {
keepDecorationsFor ( plugin , typeOfDecoration ) {
if ( ! this . currentFile ) return
if ( ! this . currentFile ) return
const { currentDecorations } = this . api . keepDecorationsFor ( this . currentFile , plugin , typeOfDecoration , this . registeredDecorations [ typeOfDecoration ] [ this . currentFile ] || [ ] , this . currentDecorations [ typeOfDecoration ] [ this . currentFile ] || [ ] )
const { currentDecorations } = this . api . keepDecorationsFor ( this . currentFile , plugin , typeOfDecoration , this . registeredDecorations [ typeOfDecoration ] [ this . currentFile ] || [ ] , this . currentDecorations [ typeOfDecoration ] [ this . currentFile ] || [ ] )
this . currentDecorations [ typeOfDecoration ] [ this . currentFile ] = currentDecorations
this . currentDecorations [ typeOfDecoration ] [ this . currentFile ] = currentDecorations
}
}
/ * *
/ * *
* Clears all the decorations and for all the sessions for the given @ arg plugin
* Clears all the decorations and for all the sessions for the given @ arg plugin
* An annotation has the following shape :
* An annotation has the following shape :
column : - 1
column : - 1
@ -485,25 +485,25 @@ class Editor extends Plugin {
type : "warning"
type : "warning"
* @ param { String } filePath
* @ param { String } filePath
* /
* /
clearAllDecorationsFor ( plugin ) {
clearAllDecorationsFor ( plugin ) {
for ( const session in this . sessions ) {
for ( const session in this . sessions ) {
this . clearDecorationsByPlugin ( session , plugin , 'sourceAnnotationsPerFile' )
this . clearDecorationsByPlugin ( session , plugin , 'sourceAnnotationsPerFile' )
this . clearDecorationsByPlugin ( session , plugin , 'markerPerFile' )
this . clearDecorationsByPlugin ( session , plugin , 'markerPerFile' )
}
}
}
}
// error markers
// error markers
async addErrorMarker ( error ) {
async addErrorMarker ( error ) {
const { from } = this . currentRequest
const { from } = this . currentRequest
this . api . addErrorMarker ( error , from )
this . api . addErrorMarker ( error , from )
}
}
async clearErrorMarkers ( sources ) {
async clearErrorMarkers ( sources ) {
const { from } = this . currentRequest
const { from } = this . currentRequest
this . api . clearErrorMarkers ( sources , from )
this . api . clearErrorMarkers ( sources , from )
}
}
/ * *
/ * *
* Clears all the annotations for the given @ arg filePath , the plugin name is retrieved from the context , if none is given , the current sesssion is used .
* Clears all the annotations for the given @ arg filePath , the plugin name is retrieved from the context , if none is given , the current sesssion is used .
* An annotation has the following shape :
* An annotation has the following shape :
column : - 1
column : - 1
@ -513,30 +513,30 @@ class Editor extends Plugin {
* @ param { String } filePath
* @ param { String } filePath
* @ param { String } plugin
* @ param { String } plugin
* /
* /
clearAnnotations ( filePath ) {
clearAnnotations ( filePath ) {
filePath = filePath || this . currentFile
filePath = filePath || this . currentFile
const { from } = this . currentRequest
const { from } = this . currentRequest
this . clearDecorationsByPlugin ( filePath , from , 'sourceAnnotationsPerFile' )
this . clearDecorationsByPlugin ( filePath , from , 'sourceAnnotationsPerFile' )
}
}
async addDecoration ( decoration , filePath , typeOfDecoration ) {
async addDecoration ( decoration , filePath , typeOfDecoration ) {
if ( ! filePath ) return
if ( ! filePath ) return
filePath = await this . call ( 'fileManager' , 'getPathFromUrl' , filePath )
filePath = await this . call ( 'fileManager' , 'getPathFromUrl' , filePath )
filePath = filePath . file
filePath = filePath . file
if ( ! this . sessions [ filePath ] ) return
if ( ! this . sessions [ filePath ] ) return
const path = filePath || this . currentFile
const path = filePath || this . currentFile
const { from } = this . currentRequest
const { from } = this . currentRequest
decoration . from = from
decoration . from = from
const { currentDecorations , registeredDecorations } = this . api . addDecoration ( decoration , path , typeOfDecoration )
const { currentDecorations , registeredDecorations } = this . api . addDecoration ( decoration , path , typeOfDecoration )
if ( ! this . registeredDecorations [ typeOfDecoration ] [ filePath ] ) this . registeredDecorations [ typeOfDecoration ] [ filePath ] = [ ]
if ( ! this . registeredDecorations [ typeOfDecoration ] [ filePath ] ) this . registeredDecorations [ typeOfDecoration ] [ filePath ] = [ ]
this . registeredDecorations [ typeOfDecoration ] [ filePath ] . push ( ... registeredDecorations )
this . registeredDecorations [ typeOfDecoration ] [ filePath ] . push ( ... registeredDecorations )
if ( ! this . currentDecorations [ typeOfDecoration ] [ filePath ] ) this . currentDecorations [ typeOfDecoration ] [ filePath ] = [ ]
if ( ! this . currentDecorations [ typeOfDecoration ] [ filePath ] ) this . currentDecorations [ typeOfDecoration ] [ filePath ] = [ ]
this . currentDecorations [ typeOfDecoration ] [ filePath ] . push ( ... currentDecorations )
this . currentDecorations [ typeOfDecoration ] [ filePath ] . push ( ... currentDecorations )
}
}
/ * *
/ * *
* Add an annotation to the current session .
* Add an annotation to the current session .
* An annotation has the following shape :
* An annotation has the following shape :
column : - 1
column : - 1
@ -546,38 +546,38 @@ class Editor extends Plugin {
* @ param { Object } annotation
* @ param { Object } annotation
* @ param { String } filePath
* @ param { String } filePath
* /
* /
async addAnnotation ( annotation , filePath ) {
async addAnnotation ( annotation , filePath ) {
filePath = filePath || this . currentFile
filePath = filePath || this . currentFile
await this . addDecoration ( annotation , filePath , 'sourceAnnotationsPerFile' )
await this . addDecoration ( annotation , filePath , 'sourceAnnotationsPerFile' )
}
}
async highlight ( position , filePath , highlightColor , opt = { focus : true } ) {
async highlight ( position , filePath , highlightColor , opt = { focus : true } ) {
filePath = filePath || this . currentFile
filePath = filePath || this . currentFile
if ( opt . focus ) {
if ( opt . focus ) {
await this . call ( 'fileManager' , 'open' , filePath )
await this . call ( 'fileManager' , 'open' , filePath )
this . scrollToLine ( position . start . line )
this . scrollToLine ( position . start . line )
}
}
await this . addDecoration ( { position } , filePath , 'markerPerFile' )
await this . addDecoration ( { position } , filePath , 'markerPerFile' )
}
}
discardHighlight ( ) {
discardHighlight ( ) {
const { from } = this . currentRequest
const { from } = this . currentRequest
for ( const session in this . sessions ) {
for ( const session in this . sessions ) {
this . clearDecorationsByPlugin ( session , from , 'markerPerFile' , this . registeredDecorations , this . currentDecorations )
this . clearDecorationsByPlugin ( session , from , 'markerPerFile' , this . registeredDecorations , this . currentDecorations )
}
}
}
}
async addLineText ( lineText , filePath ) {
async addLineText ( lineText , filePath ) {
filePath = filePath || this . currentFile
filePath = filePath || this . currentFile
await this . addDecoration ( lineText , filePath , 'lineTextPerFile' )
await this . addDecoration ( lineText , filePath , 'lineTextPerFile' )
}
}
discardLineTexts ( ) {
discardLineTexts ( ) {
const { from } = this . currentRequest
const { from } = this . currentRequest
for ( const session in this . sessions ) {
for ( const session in this . sessions ) {
this . clearDecorationsByPlugin ( session , from , 'lineTextPerFile' , this . registeredDecorations , this . currentDecorations )
this . clearDecorationsByPlugin ( session , from , 'lineTextPerFile' , this . registeredDecorations , this . currentDecorations )
}
}
}
}
}
}
module . exports = Editor
module . exports = Editor