@@ -244,13 +244,13 @@ class DialogLogFragment : DialogFragment() {
244244 return (dp * context.resources.displayMetrics.density).toInt()
245245 }
246246
247- private fun resetLogState () {
248- AnsiColorParser .reset ()
249- lineCount = 0
250- lineStart = 0
251- pendingOverwrite = false
252- logBuffer.clear ()
253- logViewRef.get()?.text = logBuffer
247+ fun release () {
248+ logViewRef.clear ()
249+ progressRef.clear()
250+ inputRowRef.clear()
251+ shellInputRef.clear()
252+ unbindStdin ()
253+ actionEventHandler = null
254254 }
255255
256256 override fun onInputRequest (prompt : String ) {
@@ -297,7 +297,7 @@ class DialogLogFragment : DialogFragment() {
297297 lineStart = 0
298298 pendingOverwrite = false
299299 logBuffer.clear()
300- logViewRef.get()?.editableText?.clear()
300+ logViewRef.get()?.text = logBuffer
301301 }
302302
303303 override fun onStart (forceStop : Runnable ? ) {
@@ -380,70 +380,74 @@ class DialogLogFragment : DialogFragment() {
380380 */
381381 private fun dispatchLogUpdate (formattedText : CharSequence ) {
382382 val logView = logViewRef.get() ? : return
383-
383+
384384 logView.post {
385385 var i = 0
386386 val len = formattedText.length
387-
387+
388388 while (i < len) {
389+ // Tìm ký tự điều khiển (\r hoặc \n) gần nhất kể từ i
389390 var j = i
390- while (j < len) {
391- val c = formattedText[j]
392- if (c == ' \r ' || c == ' \n ' ) break
393- j++
394- }
395-
391+ while (j < len && formattedText[j] != ' \r ' && formattedText[j] != ' \n ' ) j++
392+
393+ // Phần nội dung thuần trước ký tự điều khiển (hoặc tới hết chuỗi)
396394 if (j > i) {
395+ val segment = formattedText.subSequence(i, j)
397396 if (pendingOverwrite) {
398- val end = logBuffer.length
399- if (lineStart <= end) {
400- logBuffer.delete(lineStart, end)
397+ if (lineStart in 0 .. logBuffer.length) {
398+ logBuffer.delete(lineStart, logBuffer.length)
401399 }
402400 pendingOverwrite = false
403401 }
404-
405- logBuffer.append(formattedText, i, j)
402+ logBuffer.append(segment)
406403 }
407-
404+
408405 if (j < len) {
409406 when (formattedText[j]) {
410407 ' \r ' -> {
411- if (j + 1 >= len || formattedText[j + 1 ] != ' \n ' ) {
408+ // \r\n (CRLF chuẩn) chỉ là xuống dòng bình thường, bỏ qua \r
409+ val isCRLF = j + 1 < len && formattedText[j + 1 ] == ' \n '
410+ if (! isCRLF) {
411+ // Đánh dấu: nội dung tiếp theo sẽ ghi đè từ đầu dòng hiện tại
412412 pendingOverwrite = true
413413 }
414414 }
415-
416415 ' \n ' -> {
417- if (pendingOverwrite) {
418- val end = logBuffer.length
419- if (lineStart <= end) {
420- logBuffer.delete(lineStart, end)
421- }
416+ // Nếu đang chờ ghi đè mà gặp \n ngay (không có nội dung mới sau \r)
417+ // thì coi như dòng đó bị xoá trước khi xuống dòng thật
418+ if (pendingOverwrite && lineStart in 0 .. logBuffer.length) {
419+ logBuffer.delete(lineStart, logBuffer.length)
422420 pendingOverwrite = false
423421 }
424-
425422 logBuffer.append(' \n ' )
426423 lineCount++
427424 lineStart = logBuffer.length
428425 }
429426 }
427+ j++
430428 }
431-
432- i = j + 1
429+ i = j
433430 }
434-
435- logView.text = logBuffer
436-
437- val scrollView = logView.parent as ? ScrollView
438- if (scrollView != null ) {
431+
432+ (logView.editableText ? : return @post).replace(
433+ 0 ,
434+ logView.editableText.length,
435+ logBuffer
436+ )
437+
438+ // Thực hiện cuộn và giữ focus cho ô nhập liệu
439+ (logView.parent as ? ScrollView )?.let { scrollView ->
439440 scrollView.post {
441+ // 1. Cuộn ScrollView xuống cuối cùng
440442 scrollView.fullScroll(ScrollView .FOCUS_DOWN )
441-
443+
444+ // 2. Nếu ô nhập liệu đang hiện, ép hệ thống giữ con trỏ tại đây
442445 val inputRow = inputRowRef.get()
443446 val input = shellInputRef.get()
444-
445- if (inputRow?.visibility == View .VISIBLE ) {
446- input?.requestFocus()
447+ if (inputRow != null && inputRow.visibility == View .VISIBLE && input != null ) {
448+ input.post {
449+ input.requestFocus()
450+ }
447451 }
448452 }
449453 }
0 commit comments