@@ -24,6 +24,13 @@ export interface EditorSettings {
2424 buffer : number ;
2525}
2626
27+ export interface EditorOptions {
28+ line ?: number ;
29+ column ?: number ;
30+ theme ?: any ;
31+ readOnly ?: boolean ;
32+ }
33+
2734export interface EditorState {
2835 code : Code ;
2936 offset : number ;
@@ -32,6 +39,7 @@ export interface EditorState {
3239 errorLines : Map < number , string > ;
3340 settings : EditorSettings ;
3441 diffs ?: Map < number , DiffInfo > ;
42+ readOnly ?: boolean ;
3543}
3644
3745export class AnycodeEditor {
@@ -71,14 +79,16 @@ export class AnycodeEditor {
7179 private diffEnabled : boolean = false ;
7280 private originalCode ?: string ;
7381 private diffs ?: Map < number , DiffInfo > ;
82+ private readonly readOnly : boolean ;
7483
7584 constructor (
7685 initialText = '' ,
7786 filename : string = 'test.txt' ,
7887 language : string = 'javascript' ,
79- options : any = { }
88+ options : EditorOptions = { }
8089 ) {
8190 this . code = new Code ( initialText , filename , language ) ;
91+ this . readOnly = options . readOnly ?? false ;
8292 // Set initial cursor position
8393 if ( options . line !== undefined && options . column !== undefined ) {
8494 this . offset = this . code . getOffset ( options . line , options . column ) ;
@@ -114,18 +124,20 @@ export class AnycodeEditor {
114124
115125 this . codeContent = document . createElement ( 'div' ) ;
116126 this . codeContent . className = 'code' ;
117- this . codeContent . setAttribute ( "contentEditable" , "true" ) ;
127+ this . codeContent . setAttribute ( "contentEditable" , this . readOnly ? "false" : "true" ) ;
118128 this . codeContent . setAttribute ( "spellcheck" , "false" ) ;
119129 this . codeContent . setAttribute ( "autocorrect" , "off" ) ;
120130 this . codeContent . setAttribute ( "autocapitalize" , "off" ) ;
131+ if ( this . readOnly ) {
132+ this . container . classList . add ( 'readonly' ) ;
133+ }
121134
122135 this . container . appendChild ( this . buttonsColumn ) ;
123136 this . container . appendChild ( this . gutter ) ;
124137 this . container . appendChild ( this . codeContent ) ;
125138 }
126139
127140 public clean ( ) {
128- console . log ( 'clean' ) ;
129141 this . removeEventListeners ( ) ;
130142 this . offset = 0 ;
131143 this . selection = null ;
@@ -136,10 +148,12 @@ export class AnycodeEditor {
136148 }
137149
138150 public setOnChange ( func : ( t : Change ) => void ) {
151+ if ( this . readOnly ) return ;
139152 this . code . setOnChange ( func ) ;
140153 }
141154
142155 public setHistory ( changes : Change [ ] , index : number ) {
156+ if ( this . readOnly ) return ;
143157 this . code . setHistory ( changes , index ) ;
144158 }
145159
@@ -152,6 +166,62 @@ export class AnycodeEditor {
152166 }
153167 }
154168
169+ public updateTextIncremental ( newText : string ) {
170+ const currentText = this . code . getContent ( ) ;
171+ if ( currentText === newText ) return ;
172+
173+ const maxPrefix = Math . min ( currentText . length , newText . length ) ;
174+ let prefixLength = 0 ;
175+ while (
176+ prefixLength < maxPrefix
177+ && currentText . charCodeAt ( prefixLength ) === newText . charCodeAt ( prefixLength )
178+ ) {
179+ prefixLength += 1 ;
180+ }
181+
182+ let currentSuffixStart = currentText . length ;
183+ let nextSuffixStart = newText . length ;
184+ while (
185+ currentSuffixStart > prefixLength
186+ && nextSuffixStart > prefixLength
187+ && currentText . charCodeAt ( currentSuffixStart - 1 ) === newText . charCodeAt ( nextSuffixStart - 1 )
188+ ) {
189+ currentSuffixStart -= 1 ;
190+ nextSuffixStart -= 1 ;
191+ }
192+
193+ const removedLength = currentSuffixStart - prefixLength ;
194+ const insertedText = newText . slice ( prefixLength , nextSuffixStart ) ;
195+
196+ if ( removedLength === 0 && insertedText . length === 0 ) return ;
197+
198+ if ( removedLength > 0 ) {
199+ this . code . remove ( prefixLength , removedLength ) ;
200+ }
201+
202+ if ( insertedText . length > 0 ) {
203+ this . code . insert ( insertedText , prefixLength ) ;
204+ }
205+
206+ this . selection = null ;
207+ this . offset = Math . min ( this . offset , this . code . getContentLength ( ) ) ;
208+
209+ if ( this . diffEnabled && this . originalCode !== undefined ) {
210+ const updatedText = this . code . getContent ( ) ;
211+ this . diffs = computeGitChanges ( this . originalCode , updatedText ) ;
212+ } else {
213+ this . diffs = undefined ;
214+ }
215+
216+ if ( this . search . isActive ( ) ) {
217+ const matches = this . code . search ( this . search . getPattern ( ) ) ;
218+ this . search . setMatches ( matches ) ;
219+ }
220+
221+ this . renderer . renderChanges ( this . getEditorState ( ) , this . search ) ;
222+ this . verifyDiffRendering ( ) ;
223+ }
224+
155225 public getText ( ) : string {
156226 return this . code . getContent ( ) ;
157227 }
@@ -162,7 +232,9 @@ export class AnycodeEditor {
162232
163233 public async init ( ) {
164234 await this . code . init ( ) ;
165- this . setupEventListeners ( ) ;
235+ if ( ! this . readOnly ) {
236+ this . setupEventListeners ( ) ;
237+ }
166238 }
167239
168240 public getContainer ( ) : HTMLDivElement {
@@ -180,6 +252,7 @@ export class AnycodeEditor {
180252 }
181253
182254 public requestFocus ( line : number , column : number , center : boolean = false ) : void {
255+ if ( this . readOnly ) return ;
183256 this . needFocus = true ;
184257 const offset = this . code . getOffset ( line , column ) ;
185258 this . offset = offset ;
@@ -303,6 +376,7 @@ export class AnycodeEditor {
303376 buffer : this . settings . buffer ,
304377 } ,
305378 diffs : this . diffs ,
379+ readOnly : this . readOnly ,
306380 } ;
307381 }
308382
@@ -311,6 +385,7 @@ export class AnycodeEditor {
311385 }
312386
313387 public renderCursorOrSelection ( ) {
388+ if ( this . readOnly ) return ;
314389 this . renderer . renderCursorOrSelection ( this . getEditorState ( ) ) ;
315390 }
316391
0 commit comments