diff --git a/docs/4.-Adding-New-Languages.md b/docs/4.-Adding-New-Languages.md index f6470ec69..a4dbf71f0 100644 --- a/docs/4.-Adding-New-Languages.md +++ b/docs/4.-Adding-New-Languages.md @@ -508,4 +508,9 @@ In case you don't use the default layout for test source files, you can override protected File getTestFileLocation() { return super.getTestFileLocation(); } -``` \ No newline at end of file +``` + +# Adding code highlighting to the report-viewer +To ensure your language gets properly registered and its code is correctly highlighted in the report-viewer: +1) Add your language to the `ParserLanguage` enum in 'src/model/Language.ts'. As the value for the entry use its frontend name. +2) Add your language to the switch-case in `src/utils/CodeHighlighter.ts` and return the correct [highlight.js name](https://github.com/highlightjs/highlight.js/blob/main/SUPPORTED_LANGUAGES.md). If your language is not supported by default, also register the language here. \ No newline at end of file diff --git a/report-viewer/src/components/fileDisplaying/CodePanel.vue b/report-viewer/src/components/fileDisplaying/CodePanel.vue index 683ccf7bb..03ad05c72 100644 --- a/report-viewer/src/components/fileDisplaying/CodePanel.vue +++ b/report-viewer/src/components/fileDisplaying/CodePanel.vue @@ -58,7 +58,7 @@ import Interactable from '../InteractableComponent.vue' import type { Match } from '@/model/Match' import type { SubmissionFile } from '@/stores/state' import { highlight } from '@/utils/CodeHighlighter' -import type { HighlightLanguage } from '@/model/Language' +import type { ParserLanguage } from '@/model/Language' import { getMatchColor } from '@/utils/ColorUtils' const props = defineProps({ @@ -80,7 +80,7 @@ const props = defineProps({ * Language of the file. */ highlightLanguage: { - type: String as PropType, + type: String as PropType, required: true } }) diff --git a/report-viewer/src/components/fileDisplaying/FilesContainer.vue b/report-viewer/src/components/fileDisplaying/FilesContainer.vue index 7854ec6df..1ca7d0364 100644 --- a/report-viewer/src/components/fileDisplaying/FilesContainer.vue +++ b/report-viewer/src/components/fileDisplaying/FilesContainer.vue @@ -42,10 +42,10 @@ import ScrollableComponent from '../ScrollableComponent.vue' import { VueDraggableNext } from 'vue-draggable-next' import { ref, type PropType, type Ref } from 'vue' import type { MatchInSingleFile } from '@/model/MatchInSingleFile' -import type { HighlightLanguage } from '@/model/Language' import { FontAwesomeIcon } from '@fortawesome/vue-fontawesome' import { faCompressAlt } from '@fortawesome/free-solid-svg-icons' import { library } from '@fortawesome/fontawesome-svg-core' +import type { ParserLanguage } from '@/model/Language' library.add(faCompressAlt) @@ -75,7 +75,7 @@ const props = defineProps({ * Language of the files. */ highlightLanguage: { - type: String as PropType, + type: String as PropType, required: true } }) diff --git a/report-viewer/src/model/Language.ts b/report-viewer/src/model/Language.ts index a9b9b91f8..0a833f3e7 100644 --- a/report-viewer/src/model/Language.ts +++ b/report-viewer/src/model/Language.ts @@ -19,7 +19,9 @@ enum ParserLanguage { SWIFT = 'Swift Parser', TEXT = 'Text Parser (naive)', SCXML = 'SCXML (Statechart XML)', - LLVM = 'LLVMIR Parser' + LLVM = 'LLVMIR Parser', + JAVASCRIPT = 'JavaScript', + TYPESCRIPT = 'Typescript Parser' } /** @@ -37,65 +39,4 @@ function getLanguageParser(language: string): ParserLanguage { throw new Error(`Language ${language} not found`) } -/** - * Enum for the highlight.js languages - * The strings are the names of the languages in highlight.js (https://github.com/highlightjs/highlight.js/blob/main/SUPPORTED_LANGUAGES.md) - */ -enum HighlightLanguage { - JAVA = 'java', - PYTHON = 'python', - CPP = 'cpp', - C_SHARP = 'csharp', - XML = 'xml', - GO = 'go', - KOTLIN = 'kotlin', - R_LANG = 'r', - RUST = 'rust', - SCALA = 'scala', - SCHEME = 'scheme', - SWIFT = 'swift', - TEXT = 'text' -} - -/** - * Gets the highlight.js language for the given language - * @param language Language the files were parsed with - * @returns The language for highlight.js - */ -function getHighlightLanguage(language: ParserLanguage | undefined): HighlightLanguage { - switch (language) { - case ParserLanguage.PYTHON: - return HighlightLanguage.PYTHON - case ParserLanguage.CPP: - case ParserLanguage.CPP2: - return HighlightLanguage.CPP - case ParserLanguage.C_SHARP: - return HighlightLanguage.C_SHARP - case ParserLanguage.EMF_METAMODEL: - case ParserLanguage.EMF_METAMODEL_DYNAMIC: - case ParserLanguage.EMF_MODEL: - case ParserLanguage.SCXML: - return HighlightLanguage.XML - case ParserLanguage.GO: - return HighlightLanguage.GO - case ParserLanguage.KOTLIN: - return HighlightLanguage.KOTLIN - case ParserLanguage.R_LANG: - return HighlightLanguage.R_LANG - case ParserLanguage.RUST: - return HighlightLanguage.RUST - case ParserLanguage.SCALA: - return HighlightLanguage.SCALA - case ParserLanguage.SCHEME: - return HighlightLanguage.SCHEME - case ParserLanguage.SWIFT: - return HighlightLanguage.SWIFT - case ParserLanguage.TEXT: - return HighlightLanguage.TEXT - case ParserLanguage.JAVA: - default: - return HighlightLanguage.JAVA - } -} - -export { ParserLanguage, getLanguageParser, HighlightLanguage, getHighlightLanguage } +export { ParserLanguage, getLanguageParser } diff --git a/report-viewer/src/utils/CodeHighlighter.ts b/report-viewer/src/utils/CodeHighlighter.ts index 6c1d19e85..2d4b101f6 100644 --- a/report-viewer/src/utils/CodeHighlighter.ts +++ b/report-viewer/src/utils/CodeHighlighter.ts @@ -1,5 +1,8 @@ -import type { HighlightLanguage } from '@/model/Language' +import { ParserLanguage } from '@/model/Language' import hljs from 'highlight.js' +import scheme from 'highlight.js/lib/languages/scheme' +import llvm from 'highlight.js/lib/languages/llvm' +import typescript from 'highlight.js/lib/languages/typescript' /** * Hightlights the given code with the given language. @@ -10,10 +13,10 @@ import hljs from 'highlight.js' * @param lang Language to highlight the code with * @returns */ -export function highlight(code: string, lang: HighlightLanguage) { - const highlightedCode = hljs.highlight(code, { language: lang.valueOf() }).value +export function highlight(code: string, lang: ParserLanguage) { + const highlightedCode = hljs.highlight(code, { language: getHighlightLanguage(lang) }).value const openTags: string[] = [] - const formatedCode = highlightedCode + const formattedCode = highlightedCode .replace(/(]*>)|(<\/span>)|(\n)/g, (match: string) => { if (match === '\n') { return ''.repeat(openTags.length) + '\n' + openTags.join('') @@ -28,5 +31,50 @@ export function highlight(code: string, lang: HighlightLanguage) { return match }) .split('\n') - return formatedCode + return formattedCode +} + +function getHighlightLanguage(lang: ParserLanguage) { + switch (lang) { + case ParserLanguage.PYTHON: + return 'python' + case ParserLanguage.CPP: + case ParserLanguage.CPP2: + return 'cpp' + case ParserLanguage.C_SHARP: + return 'csharp' + case ParserLanguage.EMF_METAMODEL: + case ParserLanguage.EMF_METAMODEL_DYNAMIC: + case ParserLanguage.EMF_MODEL: + case ParserLanguage.SCXML: + return 'xml' + case ParserLanguage.GO: + return 'go' + case ParserLanguage.KOTLIN: + return 'kotlin' + case ParserLanguage.R_LANG: + return 'r' + case ParserLanguage.RUST: + return 'rust' + case ParserLanguage.SCALA: + return 'scala' + case ParserLanguage.SCHEME: + hljs.registerLanguage('scheme', scheme) + return 'scheme' + case ParserLanguage.SWIFT: + return 'swift' + case ParserLanguage.TEXT: + return 'plaintext' + case ParserLanguage.LLVM: + hljs.registerLanguage('llvm', llvm) + return 'llvm' + case ParserLanguage.JAVASCRIPT: + return 'javascript' + case ParserLanguage.TYPESCRIPT: + hljs.registerLanguage('typescript', typescript) + return 'typescript' + case ParserLanguage.JAVA: + default: + return 'java' + } } diff --git a/report-viewer/src/viewWrapper/ComparisonViewWrapper.vue b/report-viewer/src/viewWrapper/ComparisonViewWrapper.vue index aa5b2eed4..5555ffb15 100644 --- a/report-viewer/src/viewWrapper/ComparisonViewWrapper.vue +++ b/report-viewer/src/viewWrapper/ComparisonViewWrapper.vue @@ -18,11 +18,11 @@ import { type Ref, ref } from 'vue' import { OverviewFactory } from '@/model/factories/OverviewFactory' import ComparisonView from '@/views/ComparisonView.vue' -import { getHighlightLanguage, type HighlightLanguage } from '@/model/Language' import type { Comparison } from '@/model/Comparison' import { ComparisonFactory } from '@/model/factories/ComparisonFactory' import LoadingCircle from '@/components/LoadingCircle.vue' import { redirectOnError } from '@/router' +import type { ParserLanguage } from '@/model/Language' const props = defineProps({ firstId: { @@ -36,7 +36,7 @@ const props = defineProps({ }) const comparison: Ref = ref(null) -const language: Ref = ref(null) +const language: Ref = ref(null) // This eslint rule is disabled to allow the use of await in the setup function. Disabling this rule is safe, because the props are gathered from the url, so changing them would reload the pafe anyway. // eslint-disable-next-line vue/no-setup-props-reactivity-loss @@ -50,7 +50,7 @@ ComparisonFactory.getComparison(props.firstId, props.secondId) OverviewFactory.getOverview() .then((overview) => { - language.value = getHighlightLanguage(overview.language) + language.value = overview.language }) .catch((error) => { redirectOnError(error, 'Could not load coparison:\n') diff --git a/report-viewer/src/views/ComparisonView.vue b/report-viewer/src/views/ComparisonView.vue index 4ef337dad..54339f2bf 100644 --- a/report-viewer/src/views/ComparisonView.vue +++ b/report-viewer/src/views/ComparisonView.vue @@ -74,7 +74,7 @@ import MatchList from '@/components/fileDisplaying/MatchList.vue' import FilesContainer from '@/components/fileDisplaying/FilesContainer.vue' import { store } from '@/stores/store' import Container from '@/components/ContainerComponent.vue' -import { HighlightLanguage } from '@/model/Language' +import { ParserLanguage } from '@/model/Language' import hljsLightMode from 'highlight.js/styles/vs.css?raw' import hljsDarkMode from 'highlight.js/styles/vs2015.css?raw' import { MetricType } from '@/model/MetricType' @@ -98,7 +98,7 @@ const props = defineProps({ required: true }, language: { - type: Object as PropType, + type: Object as PropType, required: true } })