Skip to content

Commit

Permalink
display matches character precise
Browse files Browse the repository at this point in the history
  • Loading branch information
Kr0nox committed Mar 18, 2024
1 parent d8cb26e commit 202d636
Show file tree
Hide file tree
Showing 4 changed files with 187 additions and 54 deletions.
156 changes: 156 additions & 0 deletions report-viewer/src/components/fileDisplaying/CodeLine.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,156 @@
<template>
<div
class="col-span-1 col-start-2 row-span-1 flex w-full cursor-default"
:class="{ 'cursor-pointer': matches.length > 0 }"
:style="{
gridRowStart: lineNumber
}"
>
<div
v-for="(part, index) in parts"
:key="index"
class="h-full last:flex-1"
@click="matchSelected(part.match)"
:style="{
background:
part.match != undefined
? getMatchColor(0.3, part.match.match.colorIndex)
: 'hsla(0, 0%, 0%, 0)'
}"
>
<pre
v-html="part.line"
class="code-font print-excact break-child !bg-transparent print:whitespace-pre-wrap"
></pre>
</div>
</div>
</template>

<script setup lang="ts">
import type { MatchInSingleFile } from '@/model/MatchInSingleFile'
import { getMatchColor } from '@/utils/ColorUtils'
import { ref } from 'vue'
const props = defineProps({
lineNumber: {
type: Number,
required: true
},
line: {
type: String,
required: true
},
matches: {
type: Array<MatchInSingleFile>,
required: true
}
})
const emit = defineEmits(['matchSelected'])
function matchSelected(match?: MatchInSingleFile) {
if (match) {
emit('matchSelected', match)
}
}
interface MatchPart {
start: number
end: number
match?: MatchInSingleFile
}
interface Part extends MatchPart {
line: string
}
let lineIndex = ref(0)
let colIndex = ref(0)
function compParts() {
if (props.matches.length == 0) {
return [{ line: props.line, start: 0, end: props.line.length }]
}
const sortedMatches = Array.from(props.matches)
.sort((a, b) => a.startColumn - b.startColumn)
.sort((a, b) => a.start - b.start)
let matchParts: MatchPart[] = []
if (sortedMatches[0].start == props.lineNumber && sortedMatches[0].startColumn > 0) {
const end = sortedMatches[0].startColumn - 1
matchParts.push({ start: 0, end: end })
}
const start = sortedMatches[0].start == props.lineNumber ? sortedMatches[0].startColumn : 0
const end =
sortedMatches[0].end == props.lineNumber ? sortedMatches[0].endColumn : props.line.length
matchParts.push({ start: start, end: end, match: sortedMatches[0] })
let matchIndex = 1
while (matchIndex < sortedMatches.length) {
const match = sortedMatches[matchIndex]
const prevMatchPart = matchParts[matchIndex - 1]
if (prevMatchPart.end + 1 < match.startColumn) {
const end = match.startColumn - 1
matchParts.push({ start: prevMatchPart.end + 1, end: end })
}
const end = match.end == props.lineNumber ? match.endColumn : props.line.length
matchParts.push({ start: match.startColumn, end: end, match })
matchIndex++
}
if (matchParts[matchParts.length - 1].end < props.line.length) {
matchParts.push({ start: matchParts[matchParts.length - 1].end + 1, end: props.line.length })
}
let parts: Part[] = []
lineIndex.value = 0
colIndex.value = 0
for (let i = 0; i < matchParts.length; i++) {
const matchPart = matchParts[i]
const line = getNextLinePartTill(matchPart.end)
parts.push({ line, ...matchPart })
}
return parts
}
const parts = compParts()
function getNextLinePartTill(endCol: number) {
let part = ''
while (colIndex.value <= endCol && lineIndex.value < props.line.length) {
if (props.line[lineIndex.value] == '<') {
while (props.line[lineIndex.value] != '>') {
part += props.line[lineIndex.value]
lineIndex.value++
}
part += props.line[lineIndex.value]
lineIndex.value++
} else if (props.line[lineIndex.value] == '\t') {
part += ' '
lineIndex.value++
colIndex.value++
} else {
part += props.line[lineIndex.value]
lineIndex.value++
colIndex.value++
}
}
return part
}
</script>

<style scoped>
.code-font {
font-family: 'JetBrains Mono NL', monospace !important;
}
@media print {
.break-child *,
.break-child {
word-break: break-word;
}
}
</style>
77 changes: 27 additions & 50 deletions report-viewer/src/components/fileDisplaying/CodePanel.vue
Original file line number Diff line number Diff line change
Expand Up @@ -22,39 +22,31 @@

<div class="mx-1 overflow-x-auto print:!mx-0 print:overflow-x-hidden">
<div class="print:display-initial w-fit min-w-full !text-xs" :class="{ hidden: collapsed }">
<table
<div
v-if="file.data.trim() !== ''"
class="w-full print:table-auto"
:aria-describedby="`Content of file ${file.fileName}`"
class="grid w-full grid-cols-[auto_1fr] gap-x-2 print:table-auto"
>
<div
v-for="(_, index) in codeLines"
:key="index"
class="col-span-1 col-start-1 row-span-1 text-right"
:style="{
gridRowStart: index + 1
}"
>
{{ index + 1 }}
</div>
<!-- One row in table per code line -->
<tr
<CodeLine
v-for="(line, index) in codeLines"
:key="index"
class="w-full cursor-default"
:class="{ 'cursor-pointer': line.match !== null }"
@click="lineSelected(index)"
>
<!-- Line number -->
<td class="float-right pr-3">{{ index + 1 }}</td>
<!-- Code line -->
<td
class="print-excact w-full"
:style="{
background:
line.match !== null
? getMatchColor(0.3, line.match.colorIndex)
: 'hsla(0, 0%, 0%, 0)'
}"
>
<pre
v-html="line.line"
class="code-font print-excact break-child !bg-transparent print:whitespace-pre-wrap"
ref="lineRefs"
></pre>
</td>
</tr>
</table>
ref="lineRefs"
:line="line.line"
:lineNumber="index + 1"
:matches="line.matches"
@matchSelected="matchSelected"
/>
</div>

<div v-else class="flex flex-col items-start overflow-x-auto">
<i>Empty File</i>
Expand All @@ -68,12 +60,12 @@
import type { MatchInSingleFile } from '@/model/MatchInSingleFile'
import { ref, nextTick, type PropType, computed, type Ref } from 'vue'
import Interactable from '../InteractableComponent.vue'
import type { Match } from '@/model/Match'
import type { SubmissionFile } from '@/model/File'
import { highlight } from '@/utils/CodeHighlighter'
import type { Language } from '@/model/Language'
import { getMatchColor } from '@/utils/ColorUtils'
import ToolTipComponent from '../ToolTipComponent.vue'
import CodeLine from './CodeLine.vue'
import type { Match } from '@/model/Match'
const props = defineProps({
/**
Expand All @@ -99,24 +91,22 @@ const props = defineProps({
}
})
const emit = defineEmits(['lineSelected'])
const emit = defineEmits(['matchSelected'])
const collapsed = ref(true)
const lineRefs = ref<HTMLElement[]>([])
const codeLines: Ref<{ line: string; match: null | Match }[]> = computed(() =>
const codeLines: Ref<{ line: string; matches: MatchInSingleFile[] }[]> = computed(() =>
highlight(props.file.data, props.highlightLanguage).map((line, index) => {
return {
line,
match: props.matches?.find((m) => m.start <= index + 1 && index + 1 <= m.end)?.match ?? null
matches: props.matches?.filter((m) => m.start <= index + 1 && index + 1 <= m.end) ?? []
}
})
)
function lineSelected(lineIndex: number) {
if (codeLines.value[lineIndex].match !== null) {
emit('lineSelected', codeLines.value[lineIndex].match)
}
function matchSelected(match: Match) {
emit('matchSelected', match)
}
/**
Expand Down Expand Up @@ -154,16 +144,3 @@ function getFileDisplayName(file: SubmissionFile): string {
: file.fileName
}
</script>

<style scoped>
.code-font {
font-family: 'JetBrains Mono NL', monospace !important;
}
@media print {
.break-child *,
.break-child {
word-break: break-word;
}
}
</style>
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@
!matches.get(file.fileName) ? [] : (matches.get(file.fileName) as MatchInSingleFile[])
"
:highlight-language="highlightLanguage"
@line-selected="(match) => $emit('lineSelected', match)"
@match-selected="(match) => $emit('matchSelected', match)"
class="mt-1 first:mt-0"
/>
</VueDraggableNext>
Expand Down Expand Up @@ -83,7 +83,7 @@ const props = defineProps({
}
})
defineEmits(['lineSelected'])
defineEmits(['matchSelected'])
const codePanels: Ref<(typeof CodePanel)[]> = ref([])
Expand Down
4 changes: 2 additions & 2 deletions report-viewer/src/views/ComparisonView.vue
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@
:matches="comparison.matchesInFirstSubmission"
:file-owner-display-name="store().getDisplayName(comparison.firstSubmissionId)"
:highlight-language="language"
@line-selected="showMatchInSecond"
@match-selected="showMatchInSecond"
class="max-h-0 min-h-full flex-1 overflow-hidden print:max-h-none print:overflow-y-visible"
/>
<FilesContainer
Expand All @@ -94,7 +94,7 @@
:matches="comparison.matchesInSecondSubmissions"
:file-owner-display-name="store().getDisplayName(comparison.secondSubmissionId)"
:highlight-language="language"
@line-selected="showMatchInFirst"
@match-selected="showMatchInFirst"
class="max-h-0 min-h-full flex-1 overflow-hidden print:max-h-none print:overflow-y-visible"
/>
</div>
Expand Down

0 comments on commit 202d636

Please sign in to comment.