Skip to content

Commit

Permalink
CodeBlockを単体で使う場合(提出閲覧など)を想定し、syntax関連をすべてCodeBlock内に隠蔽した
Browse files Browse the repository at this point in the history
  • Loading branch information
ZOI-dayo committed Dec 16, 2024
1 parent 965bb8c commit e1cf63b
Show file tree
Hide file tree
Showing 2 changed files with 63 additions and 66 deletions.
78 changes: 49 additions & 29 deletions src/components/CodeBlock.vue
Original file line number Diff line number Diff line change
Expand Up @@ -2,41 +2,57 @@
import { onMounted, onUpdated, useTemplateRef, watch } from 'vue'
import * as monaco from 'monaco-editor'
import { shikiToMonaco } from '@shikijs/monaco'
import {
type BundledLanguage,
type BundledTheme,
createHighlighter,
type HighlighterGeneric
} from 'shiki'
import { type BundledLanguage, createHighlighter } from 'shiki'
import editorWorker from 'monaco-editor/esm/vs/editor/editor.worker?worker'
import jsonWorker from 'monaco-editor/esm/vs/language/json/json.worker?worker'
import cssWorker from 'monaco-editor/esm/vs/language/css/css.worker?worker'
import htmlWorker from 'monaco-editor/esm/vs/language/html/html.worker?worker'
import tsWorker from 'monaco-editor/esm/vs/language/typescript/ts.worker?worker'
import { type Language } from '@/api/generated'

Check failure on line 11 in src/components/CodeBlock.vue

View workflow job for this annotation

GitHub Actions / type and build check

Cannot find module '@/api/generated' or its corresponding type declarations.
const { lang } = defineProps<{
lang?: BundledLanguage
const { language } = defineProps<{
language: Language
}>()
const model = defineModel<string>()
const codeBlock = useTemplateRef('codeBlock')
const model = defineModel<string>({ required: true })
let editor: monaco.editor.IStandaloneCodeEditor | undefined
const element = useTemplateRef('codeBlock')
let highlighter = await createHighlighter({
themes: ['github-light'],
langs: []
})
let highlighter: HighlighterGeneric<BundledLanguage, BundledTheme> | undefined
// APIより得られる言語名と、それに対応したフォーマットの対応
const syntaxMapping: Map<string, BundledLanguage> = new Map(
Object.entries({
C: 'c',
'C++': 'cpp',
Java: 'java',
Python: 'python',
JavaScript: 'javascript',
Ruby: 'ruby',
Swift: 'swift',
Go: 'go',
Rust: 'rust',
Kotlin: 'kotlin'
})
)
const setLanguage = async (lang: BundledLanguage) => {
if (lang != undefined && editor != undefined) {
highlighter?.loadLanguage(lang)
monaco.languages.register({ id: lang })
monaco.editor.setModelLanguage(editor!.getModel()!, lang)
const setLanguage = async (language?: Language) => {
if (editor == undefined) return
let syntaxName: BundledLanguage | undefined
if (language != undefined && syntaxMapping.has(language.name)) {
syntaxName = syntaxMapping.get(language.name)!
await highlighter.loadLanguage(syntaxName)
monaco.languages.register({ id: syntaxName })
}
// 対応していない言語の場合、textフォーマッタを使用
monaco.editor.setModelLanguage(editor!.getModel()!, syntaxName || 'text')
}
onMounted(async () => {
if (import.meta.env.SSR) return
const configureMonacoEditor = () => {
self.MonacoEnvironment = {
getWorker(_, label) {
if (label === 'json') {
Expand All @@ -55,28 +71,32 @@ onMounted(async () => {
}
}
monaco.languages.typescript.typescriptDefaults.setEagerModelSync(true)
}
editor = monaco.editor.create(codeBlock.value!, {
value: model.value!,
onMounted(async () => {
if (import.meta.env.SSR) return
configureMonacoEditor()
editor = monaco.editor.create(element.value!, {

Check failure on line 81 in src/components/CodeBlock.vue

View workflow job for this annotation

GitHub Actions / type and build check

Argument of type 'HTMLAttributes & ReservedProps' is not assignable to parameter of type 'HTMLElement'.
value: model.value,
automaticLayout: true
})
highlighter = await createHighlighter({
themes: ['github-light'],
langs: []
})
shikiToMonaco(highlighter, monaco)
if (lang !== undefined) await setLanguage(lang!)
await setLanguage(language)
editor.getModel()?.onDidChangeContent(() => {
model.value = editor!.getValue()
})
})
onUpdated(async () => {
await setLanguage(lang!)
await setLanguage(language)
})
watch(model, () => {
if (model.value != editor?.getValue()) editor!.setValue(model.value!)
if (model.value != editor?.getValue()) editor?.setValue(model.value)
})
</script>

Expand Down
51 changes: 14 additions & 37 deletions src/components/SubmitForm.vue
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,7 @@
import CodeBlock from '@/components/CodeBlock.vue'
import PrimaryButton from '@/components/Controls/PrimaryButton.vue'
import { type Language, LanguageApi, SubmissionsApi } from '@/api/generated'

Check failure on line 4 in src/components/SubmitForm.vue

View workflow job for this annotation

GitHub Actions / type and build check

Cannot find module '@/api/generated' or its corresponding type declarations.
import { ref } from 'vue'
import type { BundledLanguage } from 'shiki/langs'
import { onMounted, ref } from 'vue'
import router from '@/router'
const { problemId } = defineProps<{
Expand All @@ -12,36 +11,13 @@ const { problemId } = defineProps<{
// ジャッジで使用可能な言語一覧
const languages = ref<Language[]>([])
new LanguageApi().getLanguages().then((res: Language[]) => (languages.value = res))
// 現在選択されている言語
const language = ref<Language>({ id: -1, name: 'none' })
// 現在選択されている言語のid (デフォルトは1)
const languageId = ref(1)
// シンタックスハイライトのスタイル (非対応の言語の場合undefined)
const syntax = ref<BundledLanguage | undefined>(undefined)
// APIより得られる言語名と、それに対応したフォーマットの対応
const syntaxMapping: Map<string, BundledLanguage> = new Map(
Object.entries({
C: 'c',
'C++': 'cpp',
Java: 'java',
Python: 'python',
JavaScript: 'javascript',
Ruby: 'ruby',
Swift: 'swift',
Go: 'go',
Rust: 'rust',
Kotlin: 'kotlin'
})
)
// APIより得られるlanguage idから、それに対応したフォーマットを返す
const getSyntax = (id: number): BundledLanguage | undefined => {
const language = languages.value.find((language) => language.id === id)
if (language != undefined && syntaxMapping.has(language!.name))
return syntaxMapping.get(language!.name)
return undefined
}
onMounted(async () => {
languages.value = await new LanguageApi().getLanguages()
language.value = languages.value[0]
})
// 入力したコード
const source = ref<string>('')
Expand All @@ -51,7 +27,7 @@ const submit = async () => {
const submission = await new SubmissionsApi().postSubmission({
problemId: problemId,
postSubmissionRequest: {
languageId: languageId.value,
languageId: language.value.id,
source: source.value
}
})
Expand All @@ -67,17 +43,18 @@ const submit = async () => {
class="fontstyle-ui-body rounded border border-border-primary px-4 py-2 text-text-primary"
@change="
(e) => {
languageId = parseInt((e.target as HTMLInputElement).value)
syntax = getSyntax(languageId)
language = languages.find(
(lang) => lang.id == parseInt((e.target as HTMLInputElement).value)
)!
}
"
>
<option v-for="language in languages" :key="language.id" :value="language.id">
{{ language.name }}
<option v-for="lang in languages" :key="lang.id" :value="lang.id">
{{ lang.name }}
</option>
</select>
<div class="fontstyle-ui-body-strong py-1">ソースコード</div>
<CodeBlock v-model="source" class="size-full" :lang="syntax" />
<CodeBlock v-model="source" class="size-full" :language="language" />
<div class="py-2">
<PrimaryButton text="提出" @click="submit" />
</div>
Expand Down

0 comments on commit e1cf63b

Please sign in to comment.