mirror of
https://codeberg.org/uzu/strudel
synced 2026-07-14 14:53:45 -04:00
Compare commits
16 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 8465517c76 | |||
| 215ab87809 | |||
| e5fe998327 | |||
| 6f75a0a62b | |||
| 0464845262 | |||
| d6ee10e05c | |||
| 36441e7b73 | |||
| 189daa3942 | |||
| d009b9592e | |||
| f7f1bd63e8 | |||
| 7d24e45692 | |||
| 612efad3eb | |||
| e7839a09a1 | |||
| 3292f88810 | |||
| 2eda047108 | |||
| c8cf1dc712 |
@@ -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)),
|
||||
)
|
||||
.filter((doc) => isValidDoc(doc) && !hasExcludedTags(doc))
|
||||
// https://codemirror.net/docs/ref/#autocomplete.Completion
|
||||
.map((doc) /*: 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] })] : [];
|
||||
|
||||
@@ -493,6 +493,9 @@ export async function midin(input) {
|
||||
otherInputs?.length ? `Also available: ${getMidiDeviceNamesString(otherInputs)}` : ''
|
||||
}`,
|
||||
);
|
||||
}
|
||||
// ensure refs for this input are initialized
|
||||
if (!refs[input]) {
|
||||
refs[input] = {};
|
||||
}
|
||||
const cc = (cc) => ref(() => refs[input][cc] || 0);
|
||||
|
||||
@@ -8,8 +8,7 @@
|
||||
"start": "astro dev",
|
||||
"build": "astro build",
|
||||
"preview": "astro preview --port 3009 --host 0.0.0.0",
|
||||
"astro": "astro",
|
||||
"postinstall": "cp node_modules/hs2js/dist/tree-sitter.wasm public && cp node_modules/hs2js/dist/tree-sitter-haskell.wasm public"
|
||||
"astro": "astro"
|
||||
},
|
||||
"dependencies": {
|
||||
"@algolia/client-search": "^5.20.0",
|
||||
|
||||
@@ -34,11 +34,11 @@ import { JsDoc } from '../../docs/JsDoc';
|
||||
|
||||
## arp
|
||||
|
||||
<JsDoc client:idle name="Pattern#arp" h={0} />
|
||||
<JsDoc client:idle name="arp" h={0} />
|
||||
|
||||
## arpWith 🧪
|
||||
|
||||
<JsDoc client:idle name="Pattern#arpWith" h={0} />
|
||||
<JsDoc client:idle name="arpWith" h={0} />
|
||||
|
||||
## struct
|
||||
|
||||
@@ -58,7 +58,7 @@ import { JsDoc } from '../../docs/JsDoc';
|
||||
|
||||
## hush
|
||||
|
||||
<JsDoc client:idle name="hush" h={0} />
|
||||
<JsDoc client:idle name="Pattern#hush" h={0} />
|
||||
|
||||
## invert
|
||||
|
||||
|
||||
@@ -339,4 +339,18 @@ global effects use the same chain for all events of the same orbit:
|
||||
|
||||
<JsDoc client:idle name="phasersweep" h={0} />
|
||||
|
||||
## Duck
|
||||
|
||||
### duckorbit
|
||||
|
||||
<JsDoc client:idle name="duckorbit" h={0} />
|
||||
|
||||
### duckattack
|
||||
|
||||
<JsDoc client:idle name="duckattack" h={0} />
|
||||
|
||||
### duckdepth
|
||||
|
||||
<JsDoc client:idle name="duckdepth" h={0} />
|
||||
|
||||
Next, we'll look at input / output via [MIDI, OSC and other methods](/learn/input-output).
|
||||
|
||||
@@ -361,6 +361,10 @@ Sampler effects are functions that can be used to change the behaviour of sample
|
||||
|
||||
<JsDoc client:idle name="splice" h={0} />
|
||||
|
||||
### scrub
|
||||
|
||||
<JsDoc client:idle name="Pattern.scrub" h={0} />{' '}
|
||||
|
||||
### speed
|
||||
|
||||
<JsDoc client:idle name="speed" h={0} />
|
||||
|
||||
@@ -69,3 +69,133 @@
|
||||
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: 12px !important;
|
||||
padding-bottom: 12px !important;
|
||||
border: 1px solid var(--foreground) !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;
|
||||
overflow: auto !important;
|
||||
background-color: var(--lineHighlight) !important;
|
||||
}
|
||||
|
||||
/* Main tooltip container */
|
||||
.autocomplete-info-tooltip {
|
||||
border-radius: 4px !important;
|
||||
color: var(--foreground);
|
||||
font-family: var(--font-family, 'SF Mono', 'Monaco', monospace);
|
||||
font-size: var(--font-size, 13px);
|
||||
line-height: 1.4;
|
||||
max-width: 600px;
|
||||
max-height: 400px;
|
||||
min-width: 400px;
|
||||
}
|
||||
|
||||
.autocomplete-info-function-name {
|
||||
font-size: 15px;
|
||||
font-weight: 600;
|
||||
color: var(--foreground);
|
||||
margin: 0 0 8px 0;
|
||||
}
|
||||
|
||||
.autocomplete-info-function-description {
|
||||
margin: 0 0 12px 0;
|
||||
color: var(--foreground);
|
||||
line-height: 1.5;
|
||||
opacity: 0.8;
|
||||
}
|
||||
|
||||
.autocomplete-info-section-title {
|
||||
font-size: 12px;
|
||||
font-weight: 600;
|
||||
color: var(--foreground);
|
||||
margin: 16px 0 6px 0;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.5px;
|
||||
}
|
||||
|
||||
.autocomplete-info-section-title:first-child {
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
.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-color: var(--lineBackground);
|
||||
border-radius: 3px;
|
||||
border-left: 2px solid var(--foreground, #555);
|
||||
}
|
||||
|
||||
.autocomplete-info-param-item:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.autocomplete-info-param-name {
|
||||
font-weight: 600;
|
||||
color: var(--variable, var(--foreground));
|
||||
margin-right: 8px;
|
||||
}
|
||||
|
||||
.autocomplete-info-param-type {
|
||||
color: var(--comment);
|
||||
font-size: 12px;
|
||||
background-color: var(--gutterForeground);
|
||||
padding: 1px 4px;
|
||||
border-radius: 2px;
|
||||
}
|
||||
|
||||
.autocomplete-info-param-desc {
|
||||
color: var(--foreground);
|
||||
font-size: 10px;
|
||||
margin-top: 4px;
|
||||
line-height: 1.4;
|
||||
opacity: 0.7;
|
||||
}
|
||||
|
||||
.autocomplete-info-examples-section {
|
||||
margin-top: 12px;
|
||||
}
|
||||
|
||||
.autocomplete-info-example-code {
|
||||
background: var(--lineBackground);
|
||||
color: var(--foreground);
|
||||
padding: 8px;
|
||||
border-radius: 3px;
|
||||
font-family: var(--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 var(--foreground, #3a3a3a);
|
||||
}
|
||||
|
||||
.autocomplete-info-tooltip::-webkit-scrollbar {
|
||||
width: 4px;
|
||||
}
|
||||
|
||||
.autocomplete-info-tooltip::-webkit-scrollbar-track {
|
||||
}
|
||||
|
||||
.autocomplete-info-tooltip::-webkit-scrollbar-thumb {
|
||||
border-radius: 2px;
|
||||
}
|
||||
|
||||
.autocomplete-info-tooltip::-webkit-scrollbar-thumb:hover {
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user