@@ -42,7 +42,7 @@ import {
4242
4343import { statusBar } from "../utils/statusBar.mjs" ;
4444import { fileDetailsPanel } from "../utils/fileDetails.mjs" ;
45- import { renderSpecialChar } from "../utils/editorUtils.mjs" ;
45+ import { eolCodeToSeq , eolCodeToName , renderSpecialChar } from "../utils/editorUtils.mjs" ;
4646
4747
4848/**
@@ -62,6 +62,7 @@ class InputWaiter {
6262
6363 this . inputTextEl = document . getElementById ( "input-text" ) ;
6464 this . inputChrEnc = 0 ;
65+ this . eolSetManually = false ;
6566 this . initEditor ( ) ;
6667
6768 this . inputWorker = null ;
@@ -92,6 +93,7 @@ class InputWaiter {
9293 fileDetailsPanel : new Compartment
9394 } ;
9495
96+ const self = this ;
9597 const initialState = EditorState . create ( {
9698 doc : null ,
9799 extensions : [
@@ -141,6 +143,15 @@ class InputWaiter {
141143 if ( e . docChanged && ! this . silentInputChange )
142144 this . inputChange ( e ) ;
143145 this . silentInputChange = false ;
146+ } ) ,
147+
148+ // Event handlers
149+ EditorView . domEventHandlers ( {
150+ paste ( event , view ) {
151+ setTimeout ( ( ) => {
152+ self . afterPaste ( event ) ;
153+ } ) ;
154+ }
144155 } )
145156 ]
146157 } ) ;
@@ -154,12 +165,35 @@ class InputWaiter {
154165 /**
155166 * Handler for EOL change events
156167 * Sets the line separator
157- * @param {string } eolVal
168+ * @param {string } eol
169+ * @param {boolean } manual - a flag for whether this was set by the user or automatically
158170 */
159- eolChange ( eolVal ) {
160- const oldInputVal = this . getInput ( ) ;
171+ eolChange ( eol , manual = false ) {
172+ const eolVal = eolCodeToSeq [ eol ] ;
173+ if ( eolVal === undefined ) return ;
174+
175+ const eolBtn = document . querySelector ( "#input-text .eol-value" ) ;
176+ if ( manual ) {
177+ this . eolSetManually = true ;
178+ eolBtn . classList . remove ( "font-italic" ) ;
179+ } else {
180+ eolBtn . classList . add ( "font-italic" ) ;
181+ }
182+
183+ if ( eolVal === this . getEOLSeq ( ) ) return ;
184+
185+ if ( ! manual ) {
186+ // Pulse
187+ eolBtn . classList . add ( "pulse" ) ;
188+ setTimeout ( ( ) => {
189+ eolBtn . classList . remove ( "pulse" ) ;
190+ } , 2000 ) ;
191+ // Alert
192+ this . app . alert ( `Input EOL separator has been changed to ${ eolCodeToName [ eol ] } ` , 5000 ) ;
193+ }
161194
162195 // Update the EOL value
196+ const oldInputVal = this . getInput ( ) ;
163197 this . inputEditorView . dispatch ( {
164198 effects : this . inputEditorConf . eol . reconfigure ( EditorState . lineSeparator . of ( eolVal ) )
165199 } ) ;
@@ -866,6 +900,49 @@ class InputWaiter {
866900 } , delay , "inputChange" , this , [ e ] ) ( ) ;
867901 }
868902
903+ /**
904+ * Handler that fires just after input paste events.
905+ * Checks whether the EOL separator or character encoding should be updated.
906+ *
907+ * @param {event } e
908+ */
909+ afterPaste ( e ) {
910+ // If EOL has been fixed, skip this.
911+ if ( this . eolSetManually ) return ;
912+
913+ const inputText = this . getInput ( ) ;
914+
915+ // Detect most likely EOL sequence
916+ const eolCharCounts = {
917+ "LF" : inputText . count ( "\u000a" ) ,
918+ "VT" : inputText . count ( "\u000b" ) ,
919+ "FF" : inputText . count ( "\u000c" ) ,
920+ "CR" : inputText . count ( "\u000d" ) ,
921+ "CRLF" : inputText . count ( "\u000d\u000a" ) ,
922+ "NEL" : inputText . count ( "\u0085" ) ,
923+ "LS" : inputText . count ( "\u2028" ) ,
924+ "PS" : inputText . count ( "\u2029" )
925+ } ;
926+
927+ // If all zero, leave alone
928+ const total = Object . values ( eolCharCounts ) . reduce ( ( acc , curr ) => {
929+ return acc + curr ;
930+ } , 0 ) ;
931+ if ( total === 0 ) return ;
932+
933+ // If CRLF not zero and more than half the highest alternative, choose CRLF
934+ const highest = Object . entries ( eolCharCounts ) . reduce ( ( acc , curr ) => {
935+ return curr [ 1 ] > acc [ 1 ] ? curr : acc ;
936+ } , [ "LF" , 0 ] ) ;
937+ if ( ( eolCharCounts . CRLF * 2 ) > highest [ 1 ] ) {
938+ this . eolChange ( "CRLF" ) ;
939+ return ;
940+ }
941+
942+ // Else choose max
943+ this . eolChange ( highest [ 0 ] ) ;
944+ }
945+
869946 /**
870947 * Handler for input dragover events.
871948 * Gives the user a visual cue to show that items can be dropped here.
@@ -1199,6 +1276,9 @@ class InputWaiter {
11991276 this . manager . output . removeAllOutputs ( ) ;
12001277 this . manager . output . terminateZipWorker ( ) ;
12011278
1279+ this . eolSetManually = false ;
1280+ this . manager . output . eolSetManually = false ;
1281+
12021282 const tabsList = document . getElementById ( "input-tabs" ) ;
12031283 const tabsListChildren = tabsList . children ;
12041284
0 commit comments