Skip to content

Commit cf6af1a

Browse files
Add line numbers (#38)
* Add textstyle to codeview to remove the need for a CompositionLocalProvider * wip line numbers * end align numbers * add line number toggle to example app * add line number toggle to example app * remove vertical divider I was trying out in swiftui version * update changelog
1 parent d43dbd5 commit cf6af1a

File tree

7 files changed

+239
-81
lines changed

7 files changed

+239
-81
lines changed

CHANGELOG.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,10 @@
1+
## [0.10.0]
2+
3+
### Added
4+
- Add toggleable line numbers to `CodeTextView` and `CodeEditText`
5+
- Updated sample app to include a toggle for line numbers
6+
- Added `textStyle` param to `CodeTextView` and `CodeEditText` for custom text styling
7+
18
## [0.9.0]
29

310
### Changed
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
package dev.snipme.androidexample
2+
3+
import androidx.compose.foundation.layout.Arrangement
4+
import androidx.compose.foundation.layout.Row
5+
import androidx.compose.foundation.layout.Spacer
6+
import androidx.compose.foundation.layout.fillMaxWidth
7+
import androidx.compose.foundation.layout.width
8+
import androidx.compose.material3.Icon
9+
import androidx.compose.material3.Surface
10+
import androidx.compose.material3.Switch
11+
import androidx.compose.material.icons.Icons
12+
import androidx.compose.material.icons.automirrored.outlined.FormatAlignLeft
13+
import androidx.compose.material.icons.filled.DarkMode
14+
import androidx.compose.material.icons.outlined.FormatAlignLeft
15+
import androidx.compose.material.icons.outlined.FormatListNumbered
16+
import androidx.compose.material.icons.outlined.LightMode
17+
import androidx.compose.material.icons.outlined.Reorder
18+
import androidx.compose.runtime.Composable
19+
import androidx.compose.ui.Alignment
20+
import androidx.compose.ui.Modifier
21+
import androidx.compose.ui.unit.dp
22+
23+
@Composable
24+
fun LineNumberSwitcher(
25+
lineNumbersEnabled: Boolean,
26+
modifier: Modifier = Modifier,
27+
onChange: (Boolean) -> Unit,
28+
) {
29+
Surface {
30+
Row(
31+
modifier = modifier.fillMaxWidth(),
32+
horizontalArrangement = Arrangement.Center,
33+
verticalAlignment = Alignment.CenterVertically,
34+
) {
35+
Spacer(Modifier.width(8.dp))
36+
Icon(Icons.Outlined.FormatListNumbered, contentDescription = "Line numbers enabled")
37+
Spacer(Modifier.width(16.dp))
38+
Switch(checked = lineNumbersEnabled, onCheckedChange = onChange)
39+
Spacer(Modifier.width(16.dp))
40+
Icon(Icons.Outlined.Reorder, contentDescription = "Dark mode")
41+
Spacer(Modifier.width(8.dp))
42+
}
43+
}
44+
}

androidExample/src/main/java/dev/snipme/androidexample/MainActivity.kt

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import androidx.compose.foundation.layout.height
1212
import androidx.compose.foundation.layout.padding
1313
import androidx.compose.foundation.layout.size
1414
import androidx.compose.material3.Divider
15+
import androidx.compose.material3.HorizontalDivider
1516
import androidx.compose.material3.MaterialTheme
1617
import androidx.compose.material3.Surface
1718
import androidx.compose.material3.Text
@@ -58,13 +59,16 @@ private val sampleCode =
5859
@Composable
5960
fun App() {
6061
val isDarkModeState = remember { mutableStateOf(false) }
62+
val areLineNumbersEnabled = remember { mutableStateOf(true) }
6163
val isDarkMode = isDarkModeState.value
64+
val lineNumbersEnabled = areLineNumbersEnabled.value
6265

6366
val highlightsState = remember {
6467
mutableStateOf(
6568
Highlights.Builder(code = sampleCode).build()
6669
)
6770
}
71+
6872
val highlights = highlightsState.value
6973

7074
fun updateSyntaxTheme(theme: SyntaxTheme) {
@@ -100,6 +104,10 @@ fun App() {
100104

101105
Spacer(Modifier.height(16.dp))
102106

107+
LineNumberSwitcher(lineNumbersEnabled, modifier = Modifier.fillMaxWidth()) { lineNumberEnabled ->
108+
areLineNumbersEnabled.value = lineNumberEnabled
109+
}
110+
103111
Text(
104112
modifier = Modifier.fillMaxWidth(),
105113
text = "KodeView",
@@ -109,11 +117,11 @@ fun App() {
109117

110118
Spacer(modifier = Modifier.size(16.dp))
111119

112-
CodeTextView(highlights = highlights)
120+
CodeTextView(highlights = highlights, showLineNumbers = lineNumbersEnabled)
113121

114122
Spacer(modifier = Modifier.size(16.dp))
115123

116-
Divider()
124+
HorizontalDivider()
117125

118126
Spacer(modifier = Modifier.size(16.dp))
119127

@@ -133,6 +141,7 @@ fun App() {
133141
disabledIndicatorColor = Color.Transparent,
134142
errorIndicatorColor = Color.Transparent,
135143
),
144+
showLineNumbers = lineNumbersEnabled,
136145
)
137146

138147
Spacer(modifier = Modifier.size(16.dp))

desktopExample/src/main/kotlin/Main.kt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,7 @@ fun main() = application {
8989
updateSyntaxTheme(highlights.getTheme().useDark(setToDarkMode)!!)
9090
}
9191

92+
9293
Spacer(Modifier.height(16.dp))
9394

9495
Text(

kodeview/src/commonMain/kotlin/dev/snipme/kodeview/view/CodeEditText.kt

Lines changed: 39 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,22 @@
11
package dev.snipme.kodeview.view
22

33
import androidx.compose.foundation.interaction.MutableInteractionSource
4-
import androidx.compose.foundation.layout.fillMaxWidth
4+
import androidx.compose.foundation.layout.*
55
import androidx.compose.foundation.text.KeyboardActions
66
import androidx.compose.foundation.text.KeyboardOptions
77
import androidx.compose.material.LocalTextStyle
8+
import androidx.compose.material.MaterialTheme
89
import androidx.compose.material.TextField
910
import androidx.compose.material.TextFieldColors
1011
import androidx.compose.material.TextFieldDefaults
12+
import androidx.compose.material3.VerticalDivider
1113
import androidx.compose.runtime.Composable
1214
import androidx.compose.runtime.LaunchedEffect
1315
import androidx.compose.runtime.mutableStateOf
1416
import androidx.compose.runtime.remember
17+
import androidx.compose.ui.Alignment
1518
import androidx.compose.ui.Modifier
19+
import androidx.compose.ui.graphics.Color
1620
import androidx.compose.ui.graphics.Shape
1721
import androidx.compose.ui.text.AnnotatedString
1822
import androidx.compose.ui.text.TextStyle
@@ -24,6 +28,7 @@ import updateIndentations
2428
import dev.snipme.highlights.Highlights
2529
import dev.snipme.highlights.model.CodeHighlight
2630
import generateAnnotatedString
31+
import androidx.compose.ui.unit.dp
2732

2833
@Composable
2934
fun CodeEditText(
@@ -47,7 +52,9 @@ fun CodeEditText(
4752
minLines: Int = 1,
4853
interactionSource: MutableInteractionSource = remember { MutableInteractionSource() },
4954
shape: Shape = TextFieldDefaults.TextFieldShape,
50-
colors: TextFieldColors = TextFieldDefaults.textFieldColors()
55+
colors: TextFieldColors = TextFieldDefaults.textFieldColors(),
56+
showLineNumbers: Boolean = false,
57+
lineNumberTextStyle: TextStyle = textStyle.copy()
5158
) {
5259
val currentText = remember {
5360
mutableStateOf(
@@ -78,26 +85,34 @@ fun CodeEditText(
7885
)
7986
}
8087

81-
TextField(
82-
modifier = modifier.fillMaxWidth(),
83-
onValueChange = ::updateNewValue,
84-
value = currentText.value,
85-
enabled = enabled,
86-
readOnly = readOnly,
87-
textStyle = textStyle,
88-
label = label,
89-
placeholder = placeholder,
90-
leadingIcon = leadingIcon,
91-
trailingIcon = trailingIcon,
92-
isError = isError,
93-
visualTransformation = visualTransformation,
94-
keyboardOptions = keyboardOptions,
95-
keyboardActions = keyboardActions,
96-
singleLine = singleLine,
97-
maxLines = maxLines,
98-
minLines = minLines,
99-
interactionSource = interactionSource,
100-
shape = shape,
101-
colors = colors,
102-
)
88+
Row(modifier = modifier) {
89+
if (showLineNumbers) {
90+
val lines = currentText.value.text.lines().size
91+
Column(horizontalAlignment = Alignment.End,) {
92+
for (i in 1..lines) {
93+
androidx.compose.material.Text(
94+
text = i.toString(),
95+
style = lineNumberTextStyle
96+
)
97+
}
98+
99+
}
100+
Spacer(modifier = Modifier.width(8.dp))
101+
}
102+
TextField(
103+
modifier = Modifier.fillMaxWidth(),
104+
onValueChange = ::updateNewValue,
105+
value = currentText.value,
106+
enabled = enabled,
107+
readOnly = readOnly,
108+
textStyle = textStyle,
109+
label = label,
110+
placeholder = placeholder,
111+
leadingIcon = leadingIcon,
112+
trailingIcon = trailingIcon,
113+
isError = isError,
114+
visualTransformation = visualTransformation,
115+
keyboardOptions = keyboardOptions,
116+
)
117+
}
103118
}

kodeview/src/commonMain/kotlin/dev/snipme/kodeview/view/CodeTextView.kt

Lines changed: 33 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,13 @@ package dev.snipme.kodeview.view
22

33
import androidx.compose.foundation.background
44
import androidx.compose.foundation.horizontalScroll
5+
import androidx.compose.foundation.layout.Column
6+
import androidx.compose.foundation.layout.Row
7+
import androidx.compose.foundation.layout.Spacer
8+
import androidx.compose.foundation.layout.width
59
import androidx.compose.foundation.rememberScrollState
610
import androidx.compose.foundation.verticalScroll
11+
import androidx.compose.material3.LocalTextStyle
712
import androidx.compose.material3.Surface
813
import androidx.compose.material3.Text
914
import androidx.compose.runtime.Composable
@@ -12,16 +17,22 @@ import androidx.compose.runtime.getValue
1217
import androidx.compose.runtime.mutableStateOf
1318
import androidx.compose.runtime.remember
1419
import androidx.compose.runtime.setValue
20+
import androidx.compose.ui.Alignment
1521
import androidx.compose.ui.Modifier
1622
import androidx.compose.ui.graphics.Color
1723
import androidx.compose.ui.text.AnnotatedString
24+
import androidx.compose.ui.text.TextStyle
25+
import androidx.compose.ui.unit.dp
1826
import dev.snipme.highlights.Highlights
1927
import generateAnnotatedString
2028

2129
@Composable
2230
fun CodeTextView(
2331
modifier: Modifier = Modifier.background(Color.Transparent),
24-
highlights: Highlights
32+
highlights: Highlights,
33+
textStyle: TextStyle = LocalTextStyle.current,
34+
showLineNumbers: Boolean = false,
35+
lineNumberTextStyle: TextStyle = textStyle.copy()
2536
) {
2637
var textState by remember {
2738
mutableStateOf(AnnotatedString(highlights.getCode()))
@@ -37,11 +48,26 @@ fun CodeTextView(
3748
modifier = modifier,
3849
color = Color.Transparent
3950
) {
40-
Text(
41-
modifier = modifier
42-
.verticalScroll(rememberScrollState())
43-
.horizontalScroll(rememberScrollState()),
44-
text = textState
45-
)
51+
Row(modifier = Modifier
52+
.verticalScroll(rememberScrollState())
53+
.horizontalScroll(rememberScrollState())
54+
) {
55+
if (showLineNumbers) {
56+
val lines = textState.text.lines().size
57+
Column(horizontalAlignment = Alignment.End) {
58+
for (i in 1..lines) {
59+
Text(
60+
text = i.toString(),
61+
style = lineNumberTextStyle,
62+
)
63+
}
64+
}
65+
Spacer(modifier = Modifier.width(8.dp))
66+
}
67+
Text(
68+
text = textState,
69+
style = textStyle
70+
)
71+
}
4672
}
4773
}

0 commit comments

Comments
 (0)