@@ -232,6 +232,10 @@ open class EditorHandlerActivity :
232232 loadPluginTabs()
233233 }
234234
235+ /* *
236+ * Persists which tabs are open (preferences only). Does **not** write project file buffers to disk;
237+ * saving is explicit or prompted (e.g. close project).
238+ */
235239 override fun onPause () {
236240 super .onPause()
237241 // Record timestamps for all currently open files before saving the cache
@@ -246,7 +250,6 @@ open class EditorHandlerActivity :
246250 if (! isOpenedFilesSaved.get()) {
247251 saveOpenedFiles()
248252 saveOpenedPluginTabs()
249- saveAllAsync(notify = false )
250253 }
251254 }
252255
@@ -271,26 +274,31 @@ open class EditorHandlerActivity :
271274 invalidateOptionsMenu()
272275 }
273276
277+ /* *
278+ * Reloads disk content into an open editor only when the file changed on disk since the last
279+ * [onPause] snapshot **and** the in-memory buffer is still clean ([CodeEditorView.isModified] is
280+ * false). Never replaces buffers with unsaved edits or touches undo history for dirty files.
281+ */
274282 private fun checkForExternalFileChanges () {
275- // Get the list of files currently managed by the ViewModel
276283 val openFiles = editorViewModel.getOpenedFiles()
277284 if (openFiles.isEmpty() || fileTimestamps.isEmpty()) return
278285
279286 lifecycleScope.launch(Dispatchers .IO ) {
280- // Check each open file
281287 openFiles.forEach { file ->
282288 val lastKnownTimestamp = fileTimestamps[file.absolutePath] ? : return @forEach
283289 val currentTimestamp = file.lastModified()
284290
285- // If the file on disk is newer.
286291 if (currentTimestamp > lastKnownTimestamp) {
287292 val newContent = runCatching { file.readText() }.getOrNull() ? : return @forEach
288293 withContext(Dispatchers .Main ) {
289- // If the editor for the new file exists AND has no unsaved changes...
290294 val editorView = getEditorForFile(file) ? : return @withContext
291295 if (editorView.isModified) return @withContext
296+ val ideEditor = editorView.editor ? : return @withContext
297+ if (ideEditor.canUndo() || ideEditor.canRedo()) {
298+ return @withContext
299+ }
292300
293- editorView.editor? .setText(newContent)
301+ ideEditor .setText(newContent)
294302 editorView.markAsSaved()
295303 updateTabs()
296304 }
@@ -341,12 +349,19 @@ open class EditorHandlerActivity :
341349 prefs.getString(PREF_KEY_OPEN_FILES_CACHE , null )
342350 } ? : return @launch
343351
352+ if (editorViewModel.getOpenedFileCount() > 0 ) {
353+ // Returning to an in-memory session (e.g. after onPause/onStop). Replaying the
354+ // snapshot would be redundant and could interfere with dirty buffers and undo.
355+ withContext(Dispatchers .IO ) { prefs.putString(PREF_KEY_OPEN_FILES_CACHE , null ) }
356+ return @launch
357+ }
358+
344359 val cache = withContext(Dispatchers .Default ) {
345360 Gson ().fromJson(jsonCache, OpenedFilesCache ::class .java)
346361 }
347362 onReadOpenedFilesCache(cache)
348363
349- // Clear the preference so it's only loaded once on startup
364+ // Clear the preference so it's only loaded once per cold restore
350365 withContext(Dispatchers .IO ) { prefs.putString(PREF_KEY_OPEN_FILES_CACHE , null ) }
351366 } catch (err: Throwable ) {
352367 log.error(" Failed to reopen recently opened files" , err)
@@ -747,6 +762,11 @@ open class EditorHandlerActivity :
747762 override fun onConfigurationChanged (newConfig : Configuration ) {
748763 super .onConfigurationChanged(newConfig)
749764
765+ val safeContent = contentOrNull ? : return
766+ for (i in 0 until safeContent.editorContainer.childCount) {
767+ (safeContent.editorContainer.getChildAt(i) as ? CodeEditorView )?.reapplyEditorDisplayPreferences()
768+ }
769+
750770 getCurrentEditor()?.editor?.apply {
751771 doOnNextLayout {
752772 cursor?.let { c -> ensurePositionVisible(c.leftLine, c.leftColumn, true ) }
@@ -1069,17 +1089,20 @@ open class EditorHandlerActivity :
10691089 nameBuilder.addPath(it, it.path)
10701090 }
10711091
1072- for (index in 0 until content.tabs.tabCount) {
1073- val file = files.getOrNull(index) ? : continue
1092+ for (tabPos in 0 until content.tabs.tabCount) {
1093+ if (isPluginTab(tabPos)) continue
1094+ val fileIndex = getFileIndexForTabPosition(tabPos)
1095+ if (fileIndex < 0 ) continue
1096+ val file = files.getOrNull(fileIndex) ? : continue
10741097 val count = dupliCount[file.name] ? : 0
10751098
1076- val isModified = getEditorAtIndex(index )?.isModified ? : false
1099+ val isModified = getEditorAtIndex(fileIndex )?.isModified ? : false
10771100 var name = if (count > 1 ) nameBuilder.getShortPath(file) else file.name
10781101 if (isModified) {
10791102 name = " *$name "
10801103 }
10811104
1082- names[index ] = name to FileExtension .Factory .forFile(file, file.isDirectory).icon
1105+ names[tabPos ] = name to FileExtension .Factory .forFile(file, file.isDirectory).icon
10831106 }
10841107
10851108 withContext(Dispatchers .Main ) {
0 commit comments