mirror of
https://codeberg.org/uzu/strudel
synced 2026-07-13 06:19:33 -04:00
fix: repl autocomplete not rendering correctly
This commit is contained in:
committed by
github.com/robase
parent
ed5bf3b3fc
commit
3292f88810
@@ -1,68 +1,91 @@
|
||||
import jsdoc from '../../doc.json';
|
||||
// import { javascriptLanguage } from '@codemirror/lang-javascript';
|
||||
import { autocompletion } from '@codemirror/autocomplete';
|
||||
import { h } from './html';
|
||||
|
||||
function plaintext(str) {
|
||||
const escapeHtml = (str) => {
|
||||
const div = document.createElement('div');
|
||||
div.innerText = str;
|
||||
return div.innerHTML;
|
||||
}
|
||||
};
|
||||
|
||||
const getDocLabel = (doc) => doc.name || doc.longname;
|
||||
const getInnerText = (html) => {
|
||||
var div = document.createElement('div');
|
||||
const stripHtml = (html) => {
|
||||
const div = document.createElement('div');
|
||||
div.innerHTML = html;
|
||||
return div.textContent || div.innerText || '';
|
||||
};
|
||||
|
||||
export function Autocomplete({ doc, label }) {
|
||||
return h`<div class="prose dark:prose-invert max-h-[400px] overflow-auto p-2">
|
||||
<h1 class="pt-0 mt-0">${label || getDocLabel(doc)}</h1>
|
||||
${doc.description}
|
||||
<ul>
|
||||
${doc.params?.map(
|
||||
({ name, type, description }) =>
|
||||
`<li>${name} : ${type.names?.join(' | ')} ${description ? ` - ${getInnerText(description)}` : ''}</li>`,
|
||||
)}
|
||||
</ul>
|
||||
<div>
|
||||
${doc.examples?.map((example) => `<div><pre>${plaintext(example)}</pre></div>`)}
|
||||
</div>
|
||||
</div>`[0];
|
||||
/*
|
||||
<pre
|
||||
className="cursor-pointer"
|
||||
onMouseDown={(e) => {
|
||||
console.log('ola!');
|
||||
navigator.clipboard.writeText(example);
|
||||
e.stopPropagation();
|
||||
}}
|
||||
>
|
||||
{example}
|
||||
</pre>
|
||||
*/
|
||||
}
|
||||
const getDocLabel = (doc) => doc.name || doc.longname;
|
||||
|
||||
const buildParamsList = (params) =>
|
||||
params?.length
|
||||
? `
|
||||
<div class="autocomplete-info-params-section">
|
||||
<h4 class="autocomplete-info-section-title">Parameters</h4>
|
||||
<ul class="autocomplete-info-params-list">
|
||||
${params
|
||||
.map(
|
||||
({ name, type, description }) => `
|
||||
<li class="autocomplete-info-param-item">
|
||||
<span class="autocomplete-info-param-name">${name}</span>
|
||||
<span class="autocomplete-info-param-type">${type.names?.join(' | ')}</span>
|
||||
${description ? `<div class="autocomplete-info-param-desc">${stripHtml(description)}</div>` : ''}
|
||||
</li>
|
||||
`,
|
||||
)
|
||||
.join('')}
|
||||
</ul>
|
||||
</div>
|
||||
`
|
||||
: '';
|
||||
|
||||
const buildExamples = (examples) =>
|
||||
examples?.length
|
||||
? `
|
||||
<div class="autocomplete-info-examples-section">
|
||||
<h4 class="autocomplete-info-section-title">Examples</h4>
|
||||
${examples
|
||||
.map(
|
||||
(example) => `
|
||||
<pre class="autocomplete-info-example-code">${escapeHtml(example)}</pre>
|
||||
`,
|
||||
)
|
||||
.join('')}
|
||||
</div>
|
||||
`
|
||||
: '';
|
||||
|
||||
export const Autocomplete = ({ doc, label }) =>
|
||||
h`
|
||||
<div class="autocomplete-info-tooltip">
|
||||
<h3 class="autocomplete-info-function-name">${label || getDocLabel(doc)}</h3>
|
||||
${doc.description ? `<p class="autocomplete-info-function-description">${doc.description}</p>` : ''}
|
||||
${buildParamsList(doc.params)}
|
||||
${buildExamples(doc.examples)}
|
||||
</div>
|
||||
`[0];
|
||||
|
||||
const isValidDoc = (doc) => {
|
||||
const label = getDocLabel(doc);
|
||||
return label && !label.startsWith('_') && !['package'].includes(doc.kind);
|
||||
};
|
||||
|
||||
const hasExcludedTags = (doc) =>
|
||||
['superdirtOnly', 'noAutocomplete'].some((tag) => doc.tags?.find((t) => t.originalTitle === tag));
|
||||
|
||||
const jsdocCompletions = jsdoc.docs
|
||||
.filter(
|
||||
(doc) =>
|
||||
getDocLabel(doc) &&
|
||||
!getDocLabel(doc).startsWith('_') &&
|
||||
!['package'].includes(doc.kind) &&
|
||||
!['superdirtOnly', 'noAutocomplete'].some((tag) => doc.tags?.find((t) => t.originalTitle === tag)),
|
||||
)
|
||||
// https://codemirror.net/docs/ref/#autocomplete.Completion
|
||||
.map((doc) /*: Completion */ => ({
|
||||
.filter((doc) => isValidDoc(doc) && !hasExcludedTags(doc))
|
||||
// https://codemirror.net/docs/ref/#autocomplete.Completion
|
||||
.map((doc) => ({
|
||||
label: getDocLabel(doc),
|
||||
// detail: 'xxx', // An optional short piece of information to show (with a different style) after the label.
|
||||
info: () => Autocomplete({ doc }),
|
||||
type: 'function', // https://codemirror.net/docs/ref/#autocomplete.Completion.type
|
||||
}));
|
||||
|
||||
export const strudelAutocomplete = (context /* : CompletionContext */) => {
|
||||
let word = context.matchBefore(/\w*/);
|
||||
if (word.from == word.to && !context.explicit) return null;
|
||||
export const strudelAutocomplete = (context) => {
|
||||
const word = context.matchBefore(/\w*/);
|
||||
if (word.from === word.to && !context.explicit) return null;
|
||||
|
||||
return {
|
||||
from: word.from,
|
||||
options: jsdocCompletions,
|
||||
@@ -74,11 +97,5 @@ export const strudelAutocomplete = (context /* : CompletionContext */) => {
|
||||
};
|
||||
};
|
||||
|
||||
export function isAutoCompletionEnabled(on) {
|
||||
return on
|
||||
? [
|
||||
autocompletion({ override: [strudelAutocomplete] }),
|
||||
//javascriptLanguage.data.of({ autocomplete: strudelAutocomplete }),
|
||||
]
|
||||
: []; // autocompletion({ override: [] })
|
||||
}
|
||||
export const isAutoCompletionEnabled = (enabled) =>
|
||||
enabled ? [autocompletion({ override: [strudelAutocomplete] })] : [];
|
||||
|
||||
@@ -69,3 +69,134 @@
|
||||
text-decoration: underline 0.18rem;
|
||||
text-underline-offset: 0.22rem;
|
||||
}
|
||||
|
||||
/* Override default styles from the codemirror inline css for autocomplete info tooltip*/
|
||||
.cm-tooltip.cm-completionInfo {
|
||||
padding: 0 !important;
|
||||
background: #1e1e1e !important;
|
||||
border: 1px solid #3a3a3a !important;
|
||||
border-radius: 4px !important;
|
||||
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.3) !important;
|
||||
max-width: 500px !important;
|
||||
min-width: 300px !important;
|
||||
max-height: 400px !important;
|
||||
white-space: normal !important;
|
||||
}
|
||||
|
||||
/* Main tooltip container */
|
||||
.autocomplete-info-tooltip {
|
||||
padding: 12px;
|
||||
color: #d4d4d4;
|
||||
font-family: 'SF Mono', 'Monaco', monospace;
|
||||
font-size: 13px;
|
||||
line-height: 1.4;
|
||||
overflow-y: auto;
|
||||
max-width: 600px;
|
||||
max-height: 400px;
|
||||
}
|
||||
|
||||
/* Function name */
|
||||
.autocomplete-info-function-name {
|
||||
font-size: 15px;
|
||||
font-weight: 600;
|
||||
color: #ffffff;
|
||||
margin: 0 0 8px 0;
|
||||
}
|
||||
|
||||
/* Function description */
|
||||
.autocomplete-info-function-description {
|
||||
margin: 0 0 12px 0;
|
||||
color: #b4b4b4;
|
||||
line-height: 1.5;
|
||||
}
|
||||
|
||||
/* Section titles */
|
||||
.autocomplete-info-section-title {
|
||||
font-size: 12px;
|
||||
font-weight: 600;
|
||||
color: #ffffff;
|
||||
margin: 16px 0 6px 0;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.5px;
|
||||
}
|
||||
|
||||
.autocomplete-info-section-title:first-child {
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
/* Parameters */
|
||||
.autocomplete-info-params-section {
|
||||
margin-top: 12px;
|
||||
}
|
||||
|
||||
.autocomplete-info-params-list {
|
||||
list-style: none;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.autocomplete-info-param-item {
|
||||
margin-bottom: 8px;
|
||||
padding: 8px;
|
||||
background: #2a2a2a;
|
||||
border-radius: 3px;
|
||||
border-left: 2px solid #555;
|
||||
}
|
||||
|
||||
.autocomplete-info-param-item:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.autocomplete-info-param-name {
|
||||
font-weight: 600;
|
||||
color: #ffffff;
|
||||
margin-right: 8px;
|
||||
}
|
||||
|
||||
.autocomplete-info-param-type {
|
||||
color: #888;
|
||||
font-size: 12px;
|
||||
background: #333;
|
||||
padding: 1px 4px;
|
||||
border-radius: 2px;
|
||||
}
|
||||
|
||||
.autocomplete-info-param-desc {
|
||||
color: #b4b4b4;
|
||||
font-size: 10px;
|
||||
margin-top: 4px;
|
||||
line-height: 1.4;
|
||||
}
|
||||
|
||||
/* Examples */
|
||||
.autocomplete-info-examples-section {
|
||||
margin-top: 12px;
|
||||
}
|
||||
|
||||
.autocomplete-info-example-code {
|
||||
background: #2a2a2a;
|
||||
color: #d4d4d4;
|
||||
padding: 8px;
|
||||
border-radius: 3px;
|
||||
font-family: 'SF Mono', 'Monaco', monospace;
|
||||
font-size: 12px;
|
||||
line-height: 1.5;
|
||||
margin: 4px 0;
|
||||
overflow-x: auto;
|
||||
white-space: pre;
|
||||
border: 1px solid #3a3a3a;
|
||||
}
|
||||
|
||||
/* Scrollbar */
|
||||
.autocomplete-info-tooltip::-webkit-scrollbar {
|
||||
width: 4px;
|
||||
}
|
||||
|
||||
.autocomplete-info-tooltip::-webkit-scrollbar-track {
|
||||
background: #2a2a2a;
|
||||
}
|
||||
|
||||
.autocomplete-info-tooltip::-webkit-scrollbar-thumb {
|
||||
background: #555;
|
||||
border-radius: 2px;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user