Skip to content

Commit

Permalink
docs(play): support js engine in the playground
Browse files Browse the repository at this point in the history
  • Loading branch information
antfu committed Aug 30, 2024
1 parent 45d1e2e commit 5b88635
Show file tree
Hide file tree
Showing 7 changed files with 144 additions and 31 deletions.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
"@antfu/ni": "^0.23.0",
"@antfu/utils": "^0.7.10",
"@iconify-json/svg-spinners": "^1.1.3",
"@shikijs/core": "^1.14.1",
"@shikijs/core": "^1.15.0",
"@types/adm-zip": "^0.5.5",
"@types/cson": "^7.20.3",
"@types/js-yaml": "^4.0.9",
Expand Down
2 changes: 1 addition & 1 deletion playground/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@
"test": "vitest"
},
"dependencies": {
"@shikijs/core": "^1.15.0",
"@vueuse/core": "^11.0.3",
"shiki": "1.0.0-beta.0",
"vue": "^3.4.38",
"vue-router": "^4.4.3"
},
Expand Down
39 changes: 30 additions & 9 deletions playground/src/App.vue
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
<script setup lang="ts">
import type { HighlighterCore } from 'shiki/core'
import { getHighlighterCore } from 'shiki/core'
import type { HighlighterCore } from '@shikijs/core'
import { createHighlighterCore, createJavaScriptRegexEngine, createWasmOnigEngine } from '@shikijs/core'
import { themes } from '../../packages/tm-themes/index'
import { grammars, injections } from '../../packages/tm-grammars/index'
import { dependencies } from '../package.json'
import SegmentControl from './SegmentControl.vue'
import { engine, grammar, isDark, theme } from './state'
import Badge from './Badge.vue'
const isDark = useDark()
const theme = useStorage('tm-theme', 'vitesse-dark')
const grammar = useStorage('tm-grammar', 'javascript')
const embedded = ref<string[]>([])
const error = ref<any>(null)
Expand All @@ -20,6 +20,10 @@ const input = ref('')
const output = ref('')
const example = ref('')
const isFetching = ref(false)
const duration = ref(0)
const jsEngine = createJavaScriptRegexEngine()
const wasmEngine = createWasmOnigEngine(() => import('@shikijs/core/wasm-inlined'))
const filteredGrammars = computed(() => {
const searchTerm = searchInputGrammar.value.trim().toLowerCase()
Expand Down Expand Up @@ -50,8 +54,10 @@ let highlighter: HighlighterCore | null = null
let fetchingTimer: ReturnType<typeof setTimeout> | undefined
async function run(fetchInput = true) {
highlighter?.dispose()
highlighter = null
error.value = null
duration.value = 0
if (fetchingTimer)
clearTimeout(fetchingTimer)
fetchingTimer = setTimeout(() => {
Expand Down Expand Up @@ -83,18 +89,19 @@ async function run(fetchInput = true) {
embedded.value = Array.from(langs.keys())
.filter(l => l !== grammar.value)
highlighter = await getHighlighterCore({
highlighter = await createHighlighterCore({
themes: [
themeObject,
],
langs: await Promise.all(Array.from(langs.values())),
loadWasm: () => import('shiki/wasm'),
engine: engine.value === 'js' ? jsEngine : wasmEngine,
})
highlight()
}
catch (e) {
error.value = e
duration.value = 0
throw e
}
finally {
Expand All @@ -106,10 +113,13 @@ async function run(fetchInput = true) {
function highlight() {
if (highlighter) {
const start = performance.now()
const result = highlighter.codeToHtml(input.value, {
lang: grammar.value,
theme: theme.value,
})
const end = performance.now()
duration.value = end - start
output.value = result
}
}
Expand Down Expand Up @@ -157,7 +167,7 @@ function share() {
}
watch(
[theme, grammar],
[theme, grammar, engine],
(n, o) => {
params.theme = theme.value
params.grammar = grammar.value
Expand Down Expand Up @@ -196,7 +206,15 @@ if (import.meta.hot) {
<a href="https://github.com/shikijs/textmate-grammars-themes" target="_blank" text-lg hover="text-primary">
Shiki TextMate Grammar & Theme Playground
</a>
<Badge :text="`Shiki v${dependencies['@shikijs/core'].replace('^', '')}`" text-sm :color="160" />
<div flex-auto />
<SegmentControl
v-model:modelValue="engine"
:options="[
{ label: 'Oniguruma', value: 'wasm' },
{ label: 'JavaScript', value: 'js' },
]"
/>
<a border="~ base rounded" p2 hover="bg-active" href="https://github.com/shikijs/textmate-grammars-themes" target="_blank">
<div i-carbon-logo-github />
</a>
Expand Down Expand Up @@ -334,6 +352,9 @@ if (import.meta.hot) {
<div i-svg-spinners-270-ring-with-bg />
Loading...
</div>
<div v-else-if="duration" op50 text-sm text-right mr-1>
Highlighting finished in <code font-bold>{{ duration.toFixed(2) }}ms</code>
</div>
</div>
</div>
</div>
Expand Down
68 changes: 68 additions & 0 deletions playground/src/Badge.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
<script setup lang="ts">
import { isDark } from './state'
const props = withDefaults(
defineProps<{
text?: string
color?: boolean | number
as?: string
size?: string
}>(),
{
color: true,
},
)
function getHashColorFromString(
name: string,
opacity: number | string = 1,
) {
if (name === 'JavaScript')
return getHsla(45, opacity)
let hash = 0
for (let i = 0; i < name.length; i++)
hash = name.charCodeAt(i) + ((hash << 5) - hash)
const hue = hash % 360
return getHsla(hue, opacity)
}
function getHsla(
hue: number,
opacity: number | string = 1,
) {
const saturation = hue === -1
? 0
: isDark.value ? 60 : 100
const lightness = isDark.value ? 70 : 20
return `hsla(${hue}, ${saturation}%, ${lightness}%, ${opacity})`
}
const style = computed(() => {
if (!props.text || props.color === false)
return {}
return {
color: typeof props.color === 'number'
? getHsla(props.color)
: getHashColorFromString(props.text),
background: typeof props.color === 'number'
? getHsla(props.color, 0.1)
: getHashColorFromString(props.text, 0.1),
}
})
const sizeClasses = computed(() => {
switch (props.size || 'sm') {
case 'sm':
return 'px-1.5 text-11px leading-1.6em'
}
return ''
})
</script>

<template>
<component :is="as || 'span'" ws-nowrap rounded :class="sizeClasses" :style>
<slot>
<span v-text="props.text" />
</slot>
</component>
</template>
31 changes: 31 additions & 0 deletions playground/src/SegmentControl.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
<script setup lang="ts">
import Badge from './Badge.vue'
defineProps<{
options: { label: string, value: string }[]
modelValue: string
}>()
defineEmits<{
(event: 'update:modelValue', newValue: string): void
}>()
</script>

<template>
<div
flex="~ gap-1 items-center" border="~ base rounded" bg-subtle p1
>
<Badge
v-for="option in options"
:key="option.value"
class="px-2 py-1 text-xs font-mono"
:class="option.value === modelValue ? '' : 'op50'"
:color="option.value === modelValue"
:aria-pressed="option.value === modelValue"
size="none"
:text="option.label"
as="button"
@click="$emit('update:modelValue', option.value)"
/>
</div>
</template>
5 changes: 5 additions & 0 deletions playground/src/state.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
export const isDark = useDark()

export const theme = useStorage('tm-theme', 'vitesse-dark')
export const grammar = useStorage('tm-grammar', 'javascript')
export const engine = useStorage<'wasm' | 'js'>('tm-use-engine', 'wasm')
28 changes: 8 additions & 20 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

0 comments on commit 5b88635

Please sign in to comment.