Fix LSP tooltip cutoff, style hover/autocomplete tooltips, add text wrapping setting (#404)
* Fix: allow tooltips to overflow code pane while keeping the same vertical and horizontal scroll behavior that we've had. Signed-off-by: Frank Noirot <frank@kittycad.io> * Style tooltips in light and dark mode * Fix: properly display autocomplete info as HTML We were parsing it from md to html, but displaying the parsed html as a string in the info box. Signed-off-by: Frank Noirot <frank@kittycad.io> * Fix z-index of command bar to show over code panel * Let user set text wrapping in editor * Style hover tooltips * Fix failing tests by not including line wrapping plugin in test mode --------- Signed-off-by: Frank Noirot <frank@kittycad.io>
This commit is contained in:
48
src/App.tsx
48
src/App.tsx
@ -10,7 +10,7 @@ import { DebugPanel } from './components/DebugPanel'
|
||||
import { v4 as uuidv4 } from 'uuid'
|
||||
import { asyncParser } from './lang/abstractSyntaxTree'
|
||||
import { _executor } from './lang/executor'
|
||||
import CodeMirror from '@uiw/react-codemirror'
|
||||
import CodeMirror, { Extension } from '@uiw/react-codemirror'
|
||||
import { linter, lintGutter } from '@codemirror/lint'
|
||||
import { ViewUpdate, EditorView } from '@codemirror/view'
|
||||
import {
|
||||
@ -54,6 +54,7 @@ import { useGlobalStateContext } from 'hooks/useGlobalStateContext'
|
||||
import { onboardingPaths } from 'routes/Onboarding'
|
||||
import { LanguageServerClient } from 'editor/lsp'
|
||||
import kclLanguage from 'editor/lsp/language'
|
||||
import { CSSRuleObject } from 'tailwindcss/types/config'
|
||||
|
||||
export function App() {
|
||||
const { code: loadedCode, project } = useLoaderData() as IndexLoaderData
|
||||
@ -138,7 +139,7 @@ export function App() {
|
||||
context: { token },
|
||||
},
|
||||
settings: {
|
||||
context: { showDebugPanel, theme, onboardingStatus },
|
||||
context: { showDebugPanel, theme, onboardingStatus, textWrapping },
|
||||
},
|
||||
} = useGlobalStateContext()
|
||||
|
||||
@ -422,17 +423,6 @@ export function App() {
|
||||
}
|
||||
}
|
||||
|
||||
const extraExtensions = useMemo(() => {
|
||||
if (TEST) return []
|
||||
return [
|
||||
lintGutter(),
|
||||
linter((_view) => {
|
||||
return kclErrToDiagnostic(useStore.getState().kclErrors)
|
||||
}),
|
||||
EditorView.lineWrapping,
|
||||
]
|
||||
}, [])
|
||||
|
||||
// So this is a bit weird, we need to initialize the lsp server and client.
|
||||
// But the server happens async so we break this into two parts.
|
||||
// Below is the client and server promise.
|
||||
@ -472,6 +462,25 @@ export function App() {
|
||||
return plugin
|
||||
}, [lspClient, isLSPServerReady])
|
||||
|
||||
const editorExtensions = useMemo(() => {
|
||||
const extensions = [lineHighlightField] as Extension[]
|
||||
|
||||
if (kclLSP) extensions.push(kclLSP)
|
||||
|
||||
// These extensions have proven to mess with vitest
|
||||
if (!TEST) {
|
||||
extensions.push(
|
||||
lintGutter(),
|
||||
linter((_view) => {
|
||||
return kclErrToDiagnostic(useStore.getState().kclErrors)
|
||||
})
|
||||
)
|
||||
if (textWrapping === 'On') extensions.push(EditorView.lineWrapping)
|
||||
}
|
||||
|
||||
return extensions
|
||||
}, [kclLSP, textWrapping])
|
||||
|
||||
return (
|
||||
<div
|
||||
className="h-screen overflow-hidden relative flex flex-col cursor-pointer select-none"
|
||||
@ -513,7 +522,7 @@ export function App() {
|
||||
<CollapsiblePanel
|
||||
title="Code"
|
||||
icon={faCode}
|
||||
className="open:!mb-2 overflow-x-hidden"
|
||||
className="open:!mb-2"
|
||||
open={openPanes.includes('code')}
|
||||
>
|
||||
<div className="px-2 py-1">
|
||||
@ -527,16 +536,13 @@ export function App() {
|
||||
</div>
|
||||
<div
|
||||
id="code-mirror-override"
|
||||
className="overflow-x-hidden h-full"
|
||||
className="full-height-subtract"
|
||||
style={{ '--height-subtract': '4.25rem' } as CSSRuleObject}
|
||||
>
|
||||
<CodeMirror
|
||||
className="h-full overflow-hidden-x"
|
||||
className="h-full"
|
||||
value={code}
|
||||
extensions={
|
||||
kclLSP
|
||||
? [kclLSP, lineHighlightField, ...extraExtensions]
|
||||
: [lineHighlightField, ...extraExtensions]
|
||||
}
|
||||
extensions={editorExtensions}
|
||||
onChange={onChange}
|
||||
onUpdate={onUpdate}
|
||||
theme={editorTheme}
|
||||
|
@ -1,5 +1,5 @@
|
||||
.panel {
|
||||
@apply relative overflow-auto z-0;
|
||||
@apply relative z-0;
|
||||
@apply bg-chalkboard-10/70 backdrop-blur-sm;
|
||||
}
|
||||
|
||||
|
@ -196,7 +196,7 @@ const CommandBar = () => {
|
||||
setCommandBarOpen(false)
|
||||
clearState()
|
||||
}}
|
||||
className="fixed inset-0 overflow-y-auto p-4 pt-[25vh]"
|
||||
className="fixed inset-0 z-40 overflow-y-auto p-4 pt-[25vh]"
|
||||
>
|
||||
<Transition.Child
|
||||
enter="duration-100 ease-out"
|
||||
@ -207,7 +207,7 @@ const CommandBar = () => {
|
||||
leaveTo="opacity-0"
|
||||
as={Fragment}
|
||||
>
|
||||
<Dialog.Overlay className="fixed z-40 inset-0 bg-chalkboard-10/70 dark:bg-chalkboard-110/50" />
|
||||
<Dialog.Overlay className="fixed inset-0 bg-chalkboard-10/70 dark:bg-chalkboard-110/50" />
|
||||
</Transition.Child>
|
||||
<Transition.Child
|
||||
enter="duration-100 ease-out"
|
||||
@ -221,7 +221,7 @@ const CommandBar = () => {
|
||||
<Combobox
|
||||
value={selectedCommand}
|
||||
onChange={handleCommandSelection}
|
||||
className="rounded relative mx-auto z-40 p-2 bg-chalkboard-10 dark:bg-chalkboard-100 border dark:border-chalkboard-70 max-w-xl w-full shadow-lg"
|
||||
className="rounded relative mx-auto p-2 bg-chalkboard-10 dark:bg-chalkboard-100 border dark:border-chalkboard-70 max-w-xl w-full shadow-lg"
|
||||
as="div"
|
||||
>
|
||||
<div className="flex gap-2 items-center">
|
||||
|
@ -208,7 +208,13 @@ export class LanguageServerPlugin implements PluginValue {
|
||||
filterText: filterText ?? label,
|
||||
}
|
||||
if (documentation) {
|
||||
completion.info = formatContents(documentation)
|
||||
completion.info = () => {
|
||||
const htmlString = formatContents(documentation)
|
||||
const htmlNode = document.createElement('div')
|
||||
htmlNode.style.display = 'contents'
|
||||
htmlNode.innerHTML = htmlString
|
||||
return { dom: htmlNode }
|
||||
}
|
||||
}
|
||||
|
||||
return completion
|
||||
|
@ -82,11 +82,22 @@ code {
|
||||
monospace;
|
||||
}
|
||||
|
||||
.full-height-subtract {
|
||||
--height-subtract: 2.25rem;
|
||||
height: 100%;
|
||||
max-height: calc(100% - var(--height-subtract));
|
||||
}
|
||||
|
||||
#code-mirror-override .cm-editor {
|
||||
@apply bg-transparent;
|
||||
@apply h-full bg-transparent;
|
||||
}
|
||||
|
||||
#code-mirror-override .cm-scroller {
|
||||
@apply h-full;
|
||||
}
|
||||
|
||||
#code-mirror-override .cm-scroller::-webkit-scrollbar {
|
||||
@apply h-0;
|
||||
}
|
||||
|
||||
#code-mirror-override .cm-activeLine,
|
||||
@ -137,14 +148,39 @@ code {
|
||||
}
|
||||
|
||||
#code-mirror-override .cm-tooltip {
|
||||
font-size: 80%;
|
||||
@apply text-xs shadow-md;
|
||||
@apply bg-chalkboard-10 text-chalkboard-80;
|
||||
@apply rounded-sm border-solid border border-chalkboard-40/30 border-l-liquid-10;
|
||||
}
|
||||
|
||||
.dark #code-mirror-override .cm-tooltip {
|
||||
@apply bg-chalkboard-110 text-chalkboard-40;
|
||||
@apply border-chalkboard-70/20 border-l-liquid-70;
|
||||
}
|
||||
|
||||
#code-mirror-override .cm-tooltip-hover {
|
||||
@apply py-1 px-2 w-max max-w-md;
|
||||
}
|
||||
|
||||
#code-mirror-override .cm-tooltip-hover .documentation {
|
||||
padding: 5;
|
||||
#code-mirror-override .cm-completionInfo {
|
||||
@apply px-4 rounded-l-none;
|
||||
@apply bg-chalkboard-10 text-liquid-90;
|
||||
@apply border-liquid-40/30;
|
||||
}
|
||||
|
||||
.dark #code-mirror-override .cm-completionInfo {
|
||||
@apply bg-liquid-120 text-liquid-50;
|
||||
@apply border-liquid-90/60;
|
||||
}
|
||||
|
||||
#code-mirror-override .cm-tooltip-autocomplete li {
|
||||
@apply px-2 py-1;
|
||||
}
|
||||
#code-mirror-override .cm-tooltip-autocomplete li[aria-selected='true'] {
|
||||
@apply bg-liquid-10 text-liquid-110;
|
||||
}
|
||||
.dark #code-mirror-override .cm-tooltip-autocomplete li[aria-selected='true'] {
|
||||
@apply bg-liquid-100 text-liquid-20;
|
||||
}
|
||||
|
||||
#code-mirror-override .cm-content {
|
||||
|
@ -62,6 +62,17 @@ export const settingsCommandBarMeta: CommandBarMeta = {
|
||||
},
|
||||
],
|
||||
},
|
||||
'Set Text Wrapping': {
|
||||
displayValue: (args: string[]) => 'Set whether text in the editor wraps',
|
||||
args: [
|
||||
{
|
||||
name: 'textWrapping',
|
||||
type: 'select',
|
||||
defaultValue: 'textWrapping',
|
||||
options: [{ name: 'On' }, { name: 'Off' }],
|
||||
},
|
||||
],
|
||||
},
|
||||
'Set Onboarding Status': {
|
||||
hide: 'both',
|
||||
},
|
||||
@ -78,6 +89,7 @@ export const settingsMachine = createMachine(
|
||||
unitSystem: UnitSystem.Imperial,
|
||||
baseUnit: 'in' as BaseUnit,
|
||||
defaultDirectory: '',
|
||||
textWrapping: 'On' as 'On' | 'Off',
|
||||
showDebugPanel: false,
|
||||
onboardingStatus: '',
|
||||
},
|
||||
@ -142,6 +154,17 @@ export const settingsMachine = createMachine(
|
||||
target: 'idle',
|
||||
internal: true,
|
||||
},
|
||||
'Set Text Wrapping': {
|
||||
actions: [
|
||||
assign({
|
||||
textWrapping: (_, event) => event.data.textWrapping,
|
||||
}),
|
||||
'persistSettings',
|
||||
'toastSuccess',
|
||||
],
|
||||
target: 'idle',
|
||||
internal: true,
|
||||
},
|
||||
'Toggle Debug Panel': {
|
||||
actions: [
|
||||
assign({
|
||||
@ -182,6 +205,7 @@ export const settingsMachine = createMachine(
|
||||
data: { unitSystem: UnitSystem }
|
||||
}
|
||||
| { type: 'Set Base Unit'; data: { baseUnit: BaseUnit } }
|
||||
| { type: 'Set Text Wrapping'; data: { textWrapping: 'On' | 'Off' } }
|
||||
| { type: 'Set Onboarding Status'; data: { onboardingStatus: string } }
|
||||
| { type: 'Toggle Debug Panel' },
|
||||
},
|
||||
|
@ -18,6 +18,7 @@ export interface Typegen0 {
|
||||
| 'Set Default Directory'
|
||||
| 'Set Default Project Name'
|
||||
| 'Set Onboarding Status'
|
||||
| 'Set Text Wrapping'
|
||||
| 'Set Theme'
|
||||
| 'Set Unit System'
|
||||
| 'Toggle Debug Panel'
|
||||
@ -26,6 +27,7 @@ export interface Typegen0 {
|
||||
| 'Set Default Directory'
|
||||
| 'Set Default Project Name'
|
||||
| 'Set Onboarding Status'
|
||||
| 'Set Text Wrapping'
|
||||
| 'Set Theme'
|
||||
| 'Set Unit System'
|
||||
| 'Toggle Debug Panel'
|
||||
@ -34,6 +36,7 @@ export interface Typegen0 {
|
||||
| 'Set Base Unit'
|
||||
| 'Set Default Directory'
|
||||
| 'Set Default Project Name'
|
||||
| 'Set Text Wrapping'
|
||||
| 'Set Theme'
|
||||
| 'Set Unit System'
|
||||
| 'Toggle Debug Panel'
|
||||
|
Reference in New Issue
Block a user