Skip to content

Commit 899081d

Browse files
committed
search tags, search for literals.
1 parent f31c556 commit 899081d

6 files changed

Lines changed: 201 additions & 42 deletions

File tree

composeApp/src/commonMain/composeResources/values/strings.xml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,8 @@
9191
<string name="dismiss">Dismiss</string>
9292
<string name="copy">Copy</string>
9393
<string name="browse_web">Browse web</string>
94+
<string name="all_elements">All elements</string>
95+
9496

9597
<string name="sign_and_deploy">Sign and deploy</string>
9698
<string name="select_file">Select file</string>
@@ -105,6 +107,7 @@
105107
<string name="tree_search_no_results">No results found</string>
106108
<string name="tree_search_result_type_node">Tree node</string>
107109
<string name="tree_search_result_type_string">String constant</string>
110+
<string name="tree_search_result_type_literal">Literal</string>
108111
<string name="tree_search_result_type_reference">Method or field reference</string>
109112

110113
<string name="lookup_popup_open_definition">Open definition of class "%1$s"?</string>

composeApp/src/commonMain/kotlin/me/lkl/dalvikus/App.kt

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@ import androidx.compose.material.icons.automirrored.outlined.ExitToApp
1010
import androidx.compose.material.icons.filled.Coffee
1111
import androidx.compose.material.icons.filled.Draw
1212
import androidx.compose.material.icons.filled.Edit
13-
import androidx.compose.material.icons.filled.Lan
1413
import androidx.compose.material.icons.filled.Settings
1514
import androidx.compose.material.icons.outlined.*
1615
import androidx.compose.material3.*
@@ -26,6 +25,7 @@ import androidx.compose.ui.text.font.FontWeight
2625
import androidx.compose.ui.unit.dp
2726
import dalvikus.composeapp.generated.resources.*
2827
import kotlinx.coroutines.launch
28+
import me.lkl.dalvikus.icons.FamilyHistory
2929
import me.lkl.dalvikus.icons.ThreadUnread
3030
import me.lkl.dalvikus.settings.DalvikusSettings
3131
import me.lkl.dalvikus.settings.shortcutToggleEditorDecompiler
@@ -184,16 +184,16 @@ internal fun Content() {
184184
}
185185
}) {
186186
Icon(
187-
if (!showTree) Icons.Outlined.Lan else Icons.Filled.Lan,
187+
imageVector = Icons.Default.FamilyHistory,
188188
contentDescription = stringResource(Res.string.nav_file_tree)
189189
)
190190
}
191191
},
192192
label = { Text(stringResource(Res.string.nav_file_tree)) },
193193
modifier = Modifier.dragAndDropTarget(
194-
shouldStartDragAndDrop = { true },
195-
target = dragAndDropTarget
196-
),
194+
shouldStartDragAndDrop = { true },
195+
target = dragAndDropTarget
196+
),
197197
)
198198
}
199199
}
Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
package me.lkl.dalvikus.icons
2+
3+
import androidx.compose.material.icons.Icons
4+
import androidx.compose.ui.graphics.Color
5+
import androidx.compose.ui.graphics.SolidColor
6+
import androidx.compose.ui.graphics.vector.ImageVector
7+
import androidx.compose.ui.graphics.vector.path
8+
import androidx.compose.ui.unit.dp
9+
10+
val Icons.Filled.FamilyHistory: ImageVector
11+
get() {
12+
if (_FamilyHistory != null) {
13+
return _FamilyHistory!!
14+
}
15+
_FamilyHistory = ImageVector.Builder(
16+
name = "Filled.FamilyHistory",
17+
defaultWidth = 24.dp,
18+
defaultHeight = 24.dp,
19+
viewportWidth = 960f,
20+
viewportHeight = 960f
21+
).apply {
22+
path(fill = SolidColor(Color(0xFFE8EAED))) {
23+
moveTo(480f, 900f)
24+
quadToRelative(-63f, 0f, -106.5f, -43.5f)
25+
reflectiveQuadTo(330f, 750f)
26+
quadToRelative(0f, -52f, 31f, -91.5f)
27+
reflectiveQuadToRelative(79f, -53.5f)
28+
verticalLineToRelative(-85f)
29+
lineTo(200f, 520f)
30+
verticalLineToRelative(-160f)
31+
lineTo(100f, 360f)
32+
verticalLineToRelative(-280f)
33+
horizontalLineToRelative(280f)
34+
verticalLineToRelative(280f)
35+
lineTo(280f, 360f)
36+
verticalLineToRelative(80f)
37+
horizontalLineToRelative(400f)
38+
verticalLineToRelative(-85f)
39+
quadToRelative(-48f, -14f, -79f, -53.5f)
40+
reflectiveQuadTo(570f, 210f)
41+
quadToRelative(0f, -63f, 43.5f, -106.5f)
42+
reflectiveQuadTo(720f, 60f)
43+
quadToRelative(63f, 0f, 106.5f, 43.5f)
44+
reflectiveQuadTo(870f, 210f)
45+
quadToRelative(0f, 52f, -31f, 91.5f)
46+
reflectiveQuadTo(760f, 355f)
47+
verticalLineToRelative(165f)
48+
lineTo(520f, 520f)
49+
verticalLineToRelative(85f)
50+
quadToRelative(48f, 14f, 79f, 53.5f)
51+
reflectiveQuadToRelative(31f, 91.5f)
52+
quadToRelative(0f, 63f, -43.5f, 106.5f)
53+
reflectiveQuadTo(480f, 900f)
54+
close()
55+
moveTo(720f, 280f)
56+
quadToRelative(29f, 0f, 49.5f, -20.5f)
57+
reflectiveQuadTo(790f, 210f)
58+
quadToRelative(0f, -29f, -20.5f, -49.5f)
59+
reflectiveQuadTo(720f, 140f)
60+
quadToRelative(-29f, 0f, -49.5f, 20.5f)
61+
reflectiveQuadTo(650f, 210f)
62+
quadToRelative(0f, 29f, 20.5f, 49.5f)
63+
reflectiveQuadTo(720f, 280f)
64+
close()
65+
moveTo(180f, 280f)
66+
horizontalLineToRelative(120f)
67+
verticalLineToRelative(-120f)
68+
lineTo(180f, 160f)
69+
verticalLineToRelative(120f)
70+
close()
71+
moveTo(480f, 820f)
72+
quadToRelative(29f, 0f, 49.5f, -20.5f)
73+
reflectiveQuadTo(550f, 750f)
74+
quadToRelative(0f, -29f, -20.5f, -49.5f)
75+
reflectiveQuadTo(480f, 680f)
76+
quadToRelative(-29f, 0f, -49.5f, 20.5f)
77+
reflectiveQuadTo(410f, 750f)
78+
quadToRelative(0f, 29f, 20.5f, 49.5f)
79+
reflectiveQuadTo(480f, 820f)
80+
close()
81+
moveTo(240f, 220f)
82+
close()
83+
moveTo(720f, 210f)
84+
close()
85+
moveTo(480f, 750f)
86+
close()
87+
}
88+
}.build()
89+
90+
return _FamilyHistory!!
91+
}
92+
93+
@Suppress("ObjectPropertyName")
94+
private var _FamilyHistory: ImageVector? = null

composeApp/src/commonMain/kotlin/me/lkl/dalvikus/tree/Search.kt

Lines changed: 28 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -2,24 +2,20 @@ package me.lkl.dalvikus.tree
22

33
import androidx.compose.material.icons.Icons
44
import androidx.compose.material.icons.filled.Abc
5-
import androidx.compose.material.icons.outlined.Abc
6-
import androidx.compose.material.icons.outlined.Category
7-
import androidx.compose.material.icons.outlined.DataObject
8-
import androidx.compose.material.icons.outlined.Interests
9-
import androidx.compose.material.icons.outlined.SubdirectoryArrowRight
10-
import androidx.compose.material.icons.outlined.Title
11-
import androidx.compose.material.icons.outlined.Water
5+
import androidx.compose.material.icons.filled.Route
126
import androidx.compose.ui.graphics.vector.ImageVector
137
import com.android.tools.smali.dexlib2.iface.Annotation
148
import com.android.tools.smali.dexlib2.iface.ClassDef
159
import com.android.tools.smali.dexlib2.iface.instruction.ReferenceInstruction
10+
import com.android.tools.smali.dexlib2.iface.instruction.WideLiteralInstruction
1611
import com.android.tools.smali.dexlib2.iface.reference.FieldReference
1712
import com.android.tools.smali.dexlib2.iface.reference.MethodReference
1813
import com.android.tools.smali.dexlib2.iface.reference.StringReference
1914
import com.android.tools.smali.dexlib2.iface.value.StringEncodedValue
20-
2115
import kotlinx.coroutines.flow.Flow
2216
import kotlinx.coroutines.flow.flow
17+
import me.lkl.dalvikus.icons.FamilyHistory
18+
import me.lkl.dalvikus.icons.ThreadUnread
2319
import me.lkl.dalvikus.tree.dex.DexEntryClassNode
2420

2521
data class SearchOptions(
@@ -30,24 +26,33 @@ data class SearchOptions(
3026
enum class TreeSearchResultType {
3127
TREE_NODE,
3228
STRING_VALUE,
33-
REFERENCE
29+
LITERAL,
30+
REFERENCE;
31+
32+
val icon: ImageVector
33+
get() = when (this) {
34+
TREE_NODE -> Icons.Default.FamilyHistory
35+
STRING_VALUE -> Icons.Default.Abc
36+
LITERAL -> Icons.Default.ThreadUnread
37+
REFERENCE -> Icons.Default.Route
38+
}
3439
}
3540

3641
data class TreeSearchResult(val node: Node, val snippet: String, val type: TreeSearchResultType) {
3742
val icon: ImageVector = when (type) {
3843
TreeSearchResultType.TREE_NODE -> node.icon
39-
TreeSearchResultType.STRING_VALUE -> Icons.Default.Abc
40-
TreeSearchResultType.REFERENCE -> Icons.Outlined.SubdirectoryArrowRight
44+
else -> type.icon
4145
}
4246
val path: String = node.getPathHistory()
4347
}
4448

4549
fun searchTreeBFS(
4650
root: Node,
4751
query: String,
48-
options: SearchOptions
52+
options: SearchOptions,
53+
maxResults: Int = 500
4954
): Flow<TreeSearchResult> = flow {
50-
// TODO search for resources.
55+
// TODO search for resources by resource name, not by literal
5156
val matcher: (String) -> Boolean = if (options.useRegex) {
5257
// Compile regex with case option
5358
val regex = try {
@@ -69,7 +74,7 @@ fun searchTreeBFS(
6974
queue.add(root)
7075

7176
var resultsFound = 0
72-
while (queue.isNotEmpty() && resultsFound < 100) {
77+
while (queue.isNotEmpty() && resultsFound < maxResults) {
7378
val current = queue.removeFirst()
7479
val path = current.getPathHistory()
7580

@@ -95,7 +100,8 @@ fun searchTreeBFS(
95100
if (instruction is ReferenceInstruction) {
96101
val ref = instruction.reference
97102
if (ref is MethodReference) {
98-
val methodSig = "${ref.definingClass}->${ref.name}(${ref.parameterTypes.joinToString("")})${ref.returnType}"
103+
val methodSig =
104+
"${ref.definingClass}->${ref.name}(${ref.parameterTypes.joinToString("")})${ref.returnType}"
99105
if (matcher(methodSig)) {
100106
emit(TreeSearchResult(current, methodSig, TreeSearchResultType.REFERENCE))
101107
resultsFound++
@@ -107,6 +113,13 @@ fun searchTreeBFS(
107113
resultsFound++
108114
}
109115
}
116+
} else if (instruction is WideLiteralInstruction) {
117+
val value = instruction.wideLiteral.toString()
118+
val hexValue = "0x${instruction.wideLiteral.toString(16).lowercase()}"
119+
if (matcher(value) || matcher(hexValue)) {
120+
emit(TreeSearchResult(current, "$value ($hexValue)", TreeSearchResultType.LITERAL))
121+
resultsFound++
122+
}
110123
}
111124
}
112125
}

composeApp/src/commonMain/kotlin/me/lkl/dalvikus/ui/LeftPanel.kt

Lines changed: 48 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ import androidx.compose.ui.unit.dp
2525
import dalvikus.composeapp.generated.resources.*
2626
import io.github.composegears.valkyrie.MatchCase
2727
import io.github.composegears.valkyrie.RegularExpression
28+
import kotlinx.coroutines.flow.filter
2829
import kotlinx.coroutines.flow.take
2930
import kotlinx.coroutines.launch
3031
import me.lkl.dalvikus.snackbarManager
@@ -227,28 +228,66 @@ private fun SearchResults(
227228
val query = searchFieldState.text
228229
var results by remember { mutableStateOf<List<TreeSearchResult>>(emptyList()) }
229230

231+
val allTypes = TreeSearchResultType.entries.toSet()
232+
var selectedTypes by remember { mutableStateOf(allTypes) }
233+
230234
// Trigger search when query changes
231-
LaunchedEffect(query, searchOptions) {
235+
LaunchedEffect(query, searchOptions, selectedTypes) {
232236
results = emptyList()
233237
if (query.isNotBlank()) {
234238
searchTreeBFS(uiTreeRoot, query as String, searchOptions)
239+
.filter { selectedTypes.contains(it.type) }
235240
.take(100)
236241
.collect { match ->
237242
results = results + match
238243
}
239244
}
240245
}
241246

247+
@Composable
248+
fun getResultTypeName(type: TreeSearchResultType): String = stringResource(
249+
when (type) {
250+
TreeSearchResultType.TREE_NODE -> Res.string.tree_search_result_type_node
251+
TreeSearchResultType.STRING_VALUE -> Res.string.tree_search_result_type_string
252+
TreeSearchResultType.REFERENCE -> Res.string.tree_search_result_type_reference
253+
TreeSearchResultType.LITERAL -> Res.string.tree_search_result_type_literal
254+
}
255+
)
256+
242257
Column(modifier.verticalScroll(rememberScrollState())) {
258+
FlowRow(
259+
modifier = Modifier
260+
.fillMaxWidth()
261+
.padding(8.dp),
262+
horizontalArrangement = Arrangement.spacedBy(8.dp)
263+
) {
264+
allTypes.forEach { type ->
265+
val label = getResultTypeName(type)
266+
FilterChip(
267+
elevation = null, // TODO remove elevation when https://youtrack.jetbrains.com/issue/CMP-2868 is fixed.
268+
selected = selectedTypes.contains(type),
269+
onClick = {
270+
selectedTypes = if (selectedTypes.contains(type)) {
271+
selectedTypes - type
272+
} else {
273+
selectedTypes + type
274+
}
275+
},
276+
leadingIcon = {
277+
Icon(
278+
imageVector = type.icon,
279+
contentDescription = label
280+
)
281+
},
282+
label = { Text(label) }
283+
)
284+
}
285+
286+
}
287+
243288
for (result in results) {
244289
val node = result.node
245-
val type = stringResource(
246-
when (result.type) {
247-
TreeSearchResultType.TREE_NODE -> Res.string.tree_search_result_type_node
248-
TreeSearchResultType.STRING_VALUE -> Res.string.tree_search_result_type_string
249-
TreeSearchResultType.REFERENCE -> Res.string.tree_search_result_type_reference
250-
}
251-
)
290+
val type = getResultTypeName(result.type)
252291
ListItem(
253292
headlineContent = {
254293
Text(
@@ -257,6 +296,7 @@ private fun SearchResults(
257296
TreeSearchResultType.TREE_NODE -> MaterialTheme.colorScheme.onSurface
258297
TreeSearchResultType.STRING_VALUE -> MaterialTheme.colorScheme.primary
259298
TreeSearchResultType.REFERENCE -> MaterialTheme.colorScheme.secondary
299+
TreeSearchResultType.LITERAL -> MaterialTheme.colorScheme.tertiary
260300
},
261301
maxLines = 1,
262302
overflow = TextOverflow.Ellipsis

0 commit comments

Comments
 (0)