11import androidx.compose.ui.graphics.Color
22import androidx.compose.ui.text.AnnotatedString
33import androidx.compose.ui.text.ExperimentalTextApi
4+ import androidx.compose.ui.text.LinkAnnotation
45import androidx.compose.ui.text.SpanStyle
6+ import androidx.compose.ui.text.TextRange
57import androidx.compose.ui.text.buildAnnotatedString
8+ import androidx.compose.ui.text.input.TextFieldValue
69import androidx.compose.ui.text.style.TextDecoration
710import kotlinx.coroutines.*
811import kotlinx.coroutines.flow.MutableStateFlow
@@ -39,7 +42,12 @@ class MainScreen(
3942 showUiMessage(" Loading file content..." )
4043 delay(1600 )
4144 withContext(Dispatchers .Main ){
42- _uiState .update { it.copy(scriptInput = fileContent) }
45+ _uiState .update { it.copy(
46+ scriptInputValue = TextFieldValue (
47+ text = fileContent,
48+ selection = TextRange .Zero
49+ )
50+ )}
4351 }
4452 showUiMessage(" " )
4553 }
@@ -48,8 +56,8 @@ class MainScreen(
4856 }
4957 }
5058
51- fun onEditScript (text : String ){
52- _uiState .update { it.copy(scriptInput = text ) }
59+ fun onEditScript (textFieldValue : TextFieldValue ){
60+ _uiState .update { it.copy(scriptInputValue = textFieldValue ) }
5361 }
5462
5563 fun runScript (){
@@ -195,7 +203,7 @@ class MainScreen(
195203
196204 scope.launch(Dispatchers .IO ) {
197205 database.saveScriptToAFile(
198- script = currentUiState.scriptInput ,
206+ script = currentUiState.scriptInputValue.text ,
199207 scope = scope
200208 )
201209 }
@@ -260,7 +268,29 @@ class MainScreen(
260268
261269 errorLocationRegex.findAll(originalAnnotatedString.text).forEach { matchResult ->
262270 val matchRange = matchResult.range
263- println (" Found match '${matchResult.value} ' at range $matchRange " )
271+ val filename = matchResult.groupValues[1 ]
272+ val lineNumber = matchResult.groupValues[2 ].toInt()
273+ val columnNumber = matchResult.groupValues[3 ].toInt()
274+
275+ println (" Found error location: $filename :$lineNumber :$columnNumber " )
276+
277+ addLink(
278+ url = LinkAnnotation .Url (
279+ url = " error://$lineNumber :$columnNumber " ,
280+ linkInteractionListener = { annotation ->
281+ val url = (annotation as LinkAnnotation .Url ).url
282+ val locationData = url.removePrefix(" error://" )
283+ val parts = locationData.split(" :" )
284+ if (parts.size == 2 ) {
285+ val line = parts[0 ].toInt()
286+ val column = parts[1 ].toInt()
287+ navigateToLocation(line, column)
288+ }
289+ }
290+ ),
291+ start = matchRange.first,
292+ end = matchRange.last + 1
293+ )
264294 addStyle(
265295 style = SpanStyle (
266296 color = if (_uiState .value.darkMode) Color (0xFF77bbd1 ) else Color .Blue ,
@@ -274,6 +304,36 @@ class MainScreen(
274304 _uiState .update { it.copy(scriptOutput = newAnnotatedString) }
275305 }
276306
307+ private fun navigateToLocation (lineNumber : Int , columnNumber : Int ) {
308+ val currentText = _uiState .value.scriptInputValue.text
309+ val lines = currentText.split(' \n ' )
310+
311+ if (lineNumber <= lines.size && lineNumber > 0 ) {
312+ var position = 0
313+ for (i in 0 until lineNumber - 1 ) {
314+ position + = lines[i].length + 1
315+ }
316+
317+ position + = (columnNumber - 1 ).coerceAtMost(lines[lineNumber - 1 ].length)
318+
319+ _uiState .update { currentState ->
320+ currentState.copy(
321+ scriptInputValue = currentState.scriptInputValue.copy(
322+ selection = TextRange (position, position)
323+ ),
324+ shouldFocusEditor = true
325+ )
326+ }
327+
328+ showUiMessage(" Navigated to line $lineNumber , column $columnNumber " )
329+ scope.launch {
330+ delay(2000 )
331+ showUiMessage(" " )
332+ _uiState .update { it.copy(shouldFocusEditor = false ) }
333+ }
334+ }
335+ }
336+
277337 fun toggleDarkMode () {
278338 val newDarkMode = ! _uiState .value.darkMode
279339 _uiState .value = _uiState .value.copy(darkMode = newDarkMode)
@@ -286,13 +346,14 @@ class MainScreen(
286346
287347 data class UiState (
288348 val darkMode : Boolean = false ,
289- val scriptInput : String = " " ,
349+ val scriptInputValue : TextFieldValue = TextFieldValue ("") ,
290350 val scriptOutput : AnnotatedString = AnnotatedString (""),
291351 val uiMessage : String = " " ,
292352 val showReadLineField : Boolean = false ,
293353 val userInput : String = " " ,
294354 val isSubmitInputClicked : Boolean? = null ,
295355 val isWaitingForInput : Boolean = false ,
296- val isProcessRunning : Boolean = false
356+ val isProcessRunning : Boolean = false ,
357+ val shouldFocusEditor : Boolean = false
297358 )
298359}
0 commit comments