@@ -8,20 +8,31 @@ import {
88 window ,
99 workspace ,
1010} from 'vscode'
11+ import { KnownProps } from 'editorconfig'
12+
1113import {
1214 InsertFinalNewline ,
1315 PreSaveTransformation ,
1416 SetEndOfLine ,
1517 TrimTrailingWhitespace ,
1618} from './transformations'
17-
1819import {
1920 applyTextEditorOptions ,
2021 resolveCoreConfig ,
2122 resolveFile ,
2223 resolveTextEditorOptions ,
2324} from './api'
2425
26+ type Charset = Exclude < KnownProps [ 'charset' ] , undefined | 'unset' >
27+ type EncodingMap = Record < Charset , TextDocument [ 'encoding' ] >
28+ const encodingMap = {
29+ 'utf-8' : 'utf8' ,
30+ 'utf-8-bom' : 'utf8bom' ,
31+ 'utf-16le' : 'utf16le' ,
32+ 'utf-16be' : 'utf16be' ,
33+ latin1 : 'iso88591' ,
34+ } as const satisfies EncodingMap
35+
2536export default class DocumentWatcher {
2637 private disposable : Disposable
2738 private preSaveTransformations : PreSaveTransformation [ ] = [
@@ -65,6 +76,8 @@ export default class DocumentWatcher {
6576 if ( path . basename ( doc . fileName ) === '.editorconfig' ) {
6677 this . log ( '.editorconfig file saved.' )
6778 }
79+ // in case document was dirty on open/text editor change
80+ this . handleDocumentEncoding ( doc )
6881 } ) ,
6982 )
7083
@@ -78,6 +91,10 @@ export default class DocumentWatcher {
7891 } ) ,
7992 )
8093
94+ subscriptions . push (
95+ workspace . onDidOpenTextDocument ( this . handleDocumentEncoding ) ,
96+ )
97+
8198 this . disposable = Disposable . from . apply ( this , subscriptions )
8299 this . log ( 'Document watcher initialized' )
83100 }
@@ -156,6 +173,39 @@ export default class DocumentWatcher {
156173 onNoActiveTextEditor : this . onNoActiveTextEditor ,
157174 onSuccess : this . onSuccess ,
158175 } )
176+ this . handleDocumentEncoding ( editor . document )
159177 }
160178 }
179+
180+ private async handleDocumentEncoding ( document : TextDocument ) {
181+ const relativePath = workspace . asRelativePath ( document . fileName )
182+ const editorconfigSettings = await resolveCoreConfig ( document , {
183+ onBeforeResolve : this . onBeforeResolve ,
184+ } )
185+
186+ const { charset } = editorconfigSettings
187+ this . log ( `${ relativePath } : Target charset is` , charset ?? 'not set' )
188+ if ( ! charset ) {
189+ return
190+ }
191+ if ( ! ( charset in encodingMap ) ) {
192+ this . log ( `${ relativePath } : Unsupported charset` )
193+ return
194+ }
195+
196+ const targetEncoding = encodingMap [ charset as keyof typeof encodingMap ]
197+ if ( targetEncoding === document . encoding ) {
198+ return
199+ }
200+
201+ if ( document . isDirty ) {
202+ this . log ( `${ relativePath } : Cannot change encoding, document is dirty` )
203+ return
204+ }
205+
206+ this . log ( `${ relativePath } : Re-opening document with ${ targetEncoding } encoding...` )
207+ await workspace . openTextDocument ( document . uri , {
208+ encoding : targetEncoding ,
209+ } )
210+ }
161211}
0 commit comments