Skip to content

Commit

Permalink
Trim the settings content to the relevant lines
Browse files Browse the repository at this point in the history
  • Loading branch information
h0tk3y committed Jun 13, 2024
1 parent 1b2da54 commit 2aa09ea
Show file tree
Hide file tree
Showing 3 changed files with 145 additions and 70 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package org.gradle.client.core.gradle.dcl

import org.gradle.internal.declarativedsl.dom.DeclarativeDocument

fun DeclarativeDocument.relevantRange(): IntRange {
val first = content.firstOrNull() ?: return IntRange.EMPTY
val last = content.last()
return IntRange(first.sourceData.indexRange.first, last.sourceData.indexRange.last)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
package org.gradle.client.ui.composables

import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
import androidx.compose.material3.TextButton
import androidx.compose.runtime.*
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.alpha
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.text.*
import org.gradle.client.ui.theme.spacing

internal data class SourceFileViewInput(
val fileIdentifier: String,
val fileContent: String,
val relevantIndicesRange: IntRange?
)

@Composable
internal fun SourcesColumn(
sources: List<SourceFileViewInput>,
highlightedSourceRangeByFileId: MutableState<Map<String, IntRange>>
) {
Column {
val sourceFileData by derivedStateOf {
sources.map { (identifier, content, relevantIndices) ->
val highlightedRangeOrNull = highlightedSourceRangeByFileId.value[identifier]
val highlightedString = sourceFileAnnotatedString(highlightedRangeOrNull, content)
val relevantHighlightedString = relevantIndices?.let { range ->
val lineBreakBeforeFocus =
highlightedString.text.take(relevantIndices.first).indexOfLast { it == '\n' } + 1

trimIndentationWhitespaces(
highlightedString.subSequence(TextRange(lineBreakBeforeFocus, range.last + 1))
)
}
SourceFileData(
identifier,
highlightedString,
relevantHighlightedString
)
}
}

sourceFileData.forEach { data ->
SourceFileTitleAndText(data.relativePath, data.annotatedSource, data.trimmedSource)
MaterialTheme.spacing.VerticalLevel4()
}
}
}



private data class SourceFileData(
val relativePath: String,
val annotatedSource: AnnotatedString,
val trimmedSource: AnnotatedString?
)

private fun sourceFileAnnotatedString(
highlightedSourceRange: IntRange?,
fileContent: String
) = buildAnnotatedString {
when {
highlightedSourceRange == null -> append(fileContent)

else -> {
append(fileContent.substring(0, highlightedSourceRange.first))
withStyle(style = SpanStyle(background = Color.Yellow)) {
append(fileContent.substring(highlightedSourceRange))
}
append(fileContent.substring(highlightedSourceRange.last + 1))
}
}
}

@Composable
private fun SourceFileTitleAndText(
fileRelativePath: String,
highlightedSource: AnnotatedString,
trimmedSource: AnnotatedString?
) {
if (trimmedSource != null) {
var isTrimmed by remember { mutableStateOf(true) }

TitleMedium(fileRelativePath)

val linesTrimmed = highlightedSource.text.lines().count() - trimmedSource.text.lines().count()
val text = if (isTrimmed)
"($linesTrimmed irrelevant lines omitted, click to show)"
else "(hide irrelevant lines)"

TextButton(onClick = {
isTrimmed = !isTrimmed
}) {
Text(text, modifier = Modifier.alpha(0.5f))
}

MaterialTheme.spacing.VerticalLevel2()
CodeBlock(Modifier.fillMaxWidth(), if (isTrimmed) trimmedSource else highlightedSource)
} else {
TitleMedium(fileRelativePath)
MaterialTheme.spacing.VerticalLevel4()
CodeBlock(Modifier.fillMaxWidth(), highlightedSource)
}
}

private
fun trimIndentationWhitespaces(annotatedString: AnnotatedString): AnnotatedString {
val lines = annotatedString.lines()
val indentation = lines.filter { it.isNotBlank() }.minOf { it.takeWhile(Char::isWhitespace).length }
return buildAnnotatedString {
var nextLineStart = 0
for ((index, line) in lines.withIndex()) {
val lineStartToTake = nextLineStart + if (line.isBlank()) 0 else indentation
val endIndex = nextLineStart + line.length + if (index != lines.lastIndex) 1 else 0
val annotatedLine = annotatedString.subSequence(lineStartToTake, endIndex)
append(annotatedLine)
nextLineStart = endIndex
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,21 +12,13 @@ import androidx.compose.material3.*
import androidx.compose.runtime.*
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.input.pointer.PointerIcon
import androidx.compose.ui.input.pointer.pointerHoverIcon
import androidx.compose.ui.text.AnnotatedString
import androidx.compose.ui.text.SpanStyle
import androidx.compose.ui.text.buildAnnotatedString
import androidx.compose.ui.text.input.KeyboardType
import androidx.compose.ui.text.withStyle
import androidx.compose.ui.unit.times
import org.gradle.client.build.action.GetResolvedDomAction
import org.gradle.client.build.model.ResolvedDomPrerequisites
import org.gradle.client.core.gradle.dcl.MutationUtils
import org.gradle.client.core.gradle.dcl.analyzer
import org.gradle.client.core.gradle.dcl.sourceIdentifier
import org.gradle.client.core.gradle.dcl.type
import org.gradle.client.core.gradle.dcl.*
import org.gradle.client.ui.build.BuildTextField
import org.gradle.client.ui.composables.*
import org.gradle.client.ui.connected.TwoPanes
Expand Down Expand Up @@ -149,9 +141,17 @@ class GetDeclarativeDocuments : GetModelAction.GetCompositeModelAction<ResolvedD
},
right = {
val sources = listOfNotNull(
SourceFileViewInput(projectResult.sourceIdentifier().fileIdentifier, buildFileContent),
SourceFileViewInput(settingsResult.sourceIdentifier().fileIdentifier, settingsFileContent)
.takeIf { hasAnyConventionContent },
SourceFileViewInput(
projectResult.sourceIdentifier().fileIdentifier,
buildFileContent,
relevantIndicesRange = null // we are interested in the whole project file content
),
SourceFileViewInput(
settingsResult.sourceIdentifier().fileIdentifier,
settingsFileContent,
// Trim the settings file to just the part that contributed the relevant conventions:
relevantIndicesRange = domWithConventions?.inputUnderlay?.document?.relevantRange()
).takeIf { hasAnyConventionContent },
)

SourcesColumn(
Expand All @@ -162,59 +162,6 @@ class GetDeclarativeDocuments : GetModelAction.GetCompositeModelAction<ResolvedD
)
}

@Composable
private fun SourcesColumn(
sources: List<SourceFileViewInput>,
highlightedSourceRangeByFileId: MutableState<Map<String, IntRange>>
) {
Column {
val sourceFileData by derivedStateOf {
sources.map { (identifier, content) ->
val highlightedRangeOrNull = highlightedSourceRangeByFileId.value[identifier]
SourceFileData(identifier, sourceFileAnnotatedString(highlightedRangeOrNull, content))
}
}

sourceFileData.forEach { data ->
SourceFileTitleAndText(data.relativePath, data.annotatedSource)
MaterialTheme.spacing.VerticalLevel4()
}
}
}

private data class SourceFileData(
val relativePath: String,
val annotatedSource: AnnotatedString
)

private fun sourceFileAnnotatedString(
highlightedSourceRange: IntRange?,
fileContent: String
) = buildAnnotatedString {
val range = highlightedSourceRange
when {
range == null -> append(fileContent)

else -> {
append(fileContent.substring(0, range.first))
withStyle(style = SpanStyle(background = Color.Yellow)) {
append(fileContent.substring(range))
}
append(fileContent.substring(range.last + 1))
}
}
}

@Composable
private fun SourceFileTitleAndText(
fileRelativePath: String,
highlightedSource: AnnotatedString
) {
TitleMedium(fileRelativePath)
MaterialTheme.spacing.VerticalLevel4()
CodeBlock(Modifier.fillMaxWidth(), highlightedSource)
}

@Composable
@OptIn(ExperimentalMaterial3Api::class)
private fun DeclarativeFileDropDown(
Expand Down Expand Up @@ -609,11 +556,6 @@ private data class HighlightingContext(
val highlightedSourceRange: MutableState<Map<String, IntRange>>
)

private data class SourceFileViewInput(
val fileIdentifier: String,
val fileContent: String
)

private fun Modifier.withHoverCursor() =
pointerHoverIcon(PointerIcon(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR)))

Expand Down

0 comments on commit 2aa09ea

Please sign in to comment.