Skip to content

Commit d9a1f55

Browse files
committed
line numbers example
1 parent 599cc79 commit d9a1f55

File tree

4 files changed

+106
-24
lines changed

4 files changed

+106
-24
lines changed
0 Bytes
Binary file not shown.
60.2 KB
Binary file not shown.

README.md

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -140,6 +140,66 @@ OutlinedTextField(
140140
)
141141
```
142142

143+
### Displaying Line Numbers
144+
145+
To display line numbers in the text field we must use a `BasicTextField` since it has a parameter for `onTextLayout`
146+
147+
A basic example can be setup like this , On every text layout a new array is created
148+
which contains top offsets of each line in the `BasicTextField`
149+
150+
```kotlin
151+
152+
val language = CodeLang.Kotlin
153+
val code = """
154+
package com.wakaztahir.codeeditor
155+
156+
fun main(){
157+
println("Hello World");
158+
}
159+
""".trimIndent()
160+
161+
val parser = remember { PrettifyParser() }
162+
val themeState by remember { mutableStateOf(CodeThemeType.Default) }
163+
val theme = remember(themeState) { themeState.theme }
164+
165+
fun parse(code: String): AnnotatedString {
166+
return parseCodeAsAnnotatedString(
167+
parser = parser,
168+
theme = theme,
169+
lang = language,
170+
code = code
171+
)
172+
}
173+
174+
var textFieldValue by remember { mutableStateOf(TextFieldValue(parse(code))) }
175+
var lineTops by remember { mutableStateOf(emptyArray<Float>()) }
176+
val density = LocalDensity.current
177+
178+
Row {
179+
if (lineTops.isNotEmpty()) {
180+
Box(modifier = Modifier.padding(horizontal = 4.dp)) {
181+
lineTops.forEachIndexed { index, top ->
182+
Text(
183+
modifier = Modifier.offset(y = with(density) { top.toDp() }),
184+
text = index.toString(),
185+
color = MaterialTheme.colors.onBackground.copy(.3f)
186+
)
187+
}
188+
}
189+
}
190+
BasicTextField(
191+
modifier = Modifier.fillMaxSize(),
192+
value = textFieldValue,
193+
onValueChange = {
194+
textFieldValue = it.copy(annotatedString = parse(it.text))
195+
},
196+
onTextLayout = { result ->
197+
lineTops = Array(result.lineCount) { result.getLineTop(it) }
198+
}
199+
)
200+
}
201+
```
202+
143203
## List of available languages & their extensions
144204

145205
Default (```"default-code"```), HTML (```"default-markup"```) , C/C++/Objective-C (```"c"```, ```"cc"```, ```"cpp"```, ```"cxx"```, ```"cyc"```, ```"m"```),
Lines changed: 46 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,26 @@
11
package com.wakaztahir.common
22

3-
import androidx.compose.foundation.layout.fillMaxSize
3+
import androidx.compose.foundation.background
4+
import androidx.compose.foundation.layout.*
5+
import androidx.compose.foundation.text.BasicTextField
6+
import androidx.compose.material.MaterialTheme
47
import androidx.compose.material.OutlinedTextField
8+
import androidx.compose.material.Text
9+
import androidx.compose.material.primarySurface
510
import androidx.compose.runtime.*
611
import androidx.compose.ui.Modifier
12+
import androidx.compose.ui.geometry.Offset
13+
import androidx.compose.ui.platform.LocalDensity
14+
import androidx.compose.ui.text.AnnotatedString
715
import androidx.compose.ui.text.input.TextFieldValue
16+
import androidx.compose.ui.unit.DpOffset
17+
import androidx.compose.ui.unit.IntOffset
18+
import androidx.compose.ui.unit.dp
819
import com.wakaztahir.codeeditor.model.CodeLang
920
import com.wakaztahir.codeeditor.prettify.PrettifyParser
1021
import com.wakaztahir.codeeditor.theme.CodeThemeType
1122
import com.wakaztahir.codeeditor.utils.parseCodeAsAnnotatedString
23+
import kotlin.math.roundToInt
1224

1325
@Composable
1426
fun DisplayCodeEditor() {
@@ -24,31 +36,41 @@ fun DisplayCodeEditor() {
2436
val parser = remember { PrettifyParser() }
2537
val themeState by remember { mutableStateOf(CodeThemeType.Default) }
2638
val theme = remember(themeState) { themeState.theme }
27-
var textFieldValue by remember {
28-
mutableStateOf(
29-
TextFieldValue(
30-
annotatedString = parseCodeAsAnnotatedString(
31-
parser = parser,
32-
theme = theme,
33-
lang = language,
34-
code = code
35-
)
36-
)
39+
40+
fun parse(code: String): AnnotatedString {
41+
return parseCodeAsAnnotatedString(
42+
parser = parser,
43+
theme = theme,
44+
lang = language,
45+
code = code
3746
)
3847
}
3948

40-
OutlinedTextField(
41-
modifier = Modifier.fillMaxSize(),
42-
value = textFieldValue,
43-
onValueChange = {
44-
textFieldValue = it.copy(
45-
annotatedString = parseCodeAsAnnotatedString(
46-
parser = parser,
47-
theme = theme,
48-
lang = language,
49-
code = it.text
50-
)
51-
)
49+
var textFieldValue by remember { mutableStateOf(TextFieldValue(parse(code))) }
50+
var lineTops by remember { mutableStateOf(emptyArray<Float>()) }
51+
val density = LocalDensity.current
52+
53+
Row {
54+
if (lineTops.isNotEmpty()) {
55+
Box(modifier = Modifier.padding(horizontal = 4.dp)) {
56+
lineTops.forEachIndexed { index, top ->
57+
Text(
58+
modifier = Modifier.offset(y = with(density) { top.toDp() }),
59+
text = index.toString(),
60+
color = MaterialTheme.colors.onBackground.copy(.3f)
61+
)
62+
}
63+
}
5264
}
53-
)
65+
BasicTextField(
66+
modifier = Modifier.fillMaxSize(),
67+
value = textFieldValue,
68+
onValueChange = {
69+
textFieldValue = it.copy(annotatedString = parse(it.text))
70+
},
71+
onTextLayout = { result ->
72+
lineTops = Array(result.lineCount) { result.getLineTop(it) }
73+
}
74+
)
75+
}
5476
}

0 commit comments

Comments
 (0)