AI: attempt to add autocomplete
This commit is contained in:
+166
-24
@@ -1,12 +1,18 @@
|
||||
Write-Host "===================================================" -ForegroundColor Cyan
|
||||
Write-Host "1/2 Compiling ANTLR Grammars" -ForegroundColor Cyan
|
||||
Write-Host "===================================================" -ForegroundColor Cyan
|
||||
param(
|
||||
[switch]$SkipAntlr
|
||||
)
|
||||
|
||||
Write-Host "Compiling legacy version (ANTLR 4.9.3)..." -ForegroundColor Yellow
|
||||
antlr4 -v 4.9.3 -Dlanguage=Python3 -visitor -o ./legacy MathExpr.g4
|
||||
if (-not $SkipAntlr) {
|
||||
Write-Host "===================================================" -ForegroundColor Cyan
|
||||
Write-Host "1/2 Compiling ANTLR Grammars" -ForegroundColor Cyan
|
||||
Write-Host "===================================================" -ForegroundColor Cyan
|
||||
|
||||
Write-Host "Compiling modern version (ANTLR 4.13.2)..." -ForegroundColor Yellow
|
||||
antlr4 -v 4.13.2 -Dlanguage=Python3 -visitor -o ./grammer MathExpr.g4
|
||||
Write-Host "Compiling legacy version (ANTLR 4.9.3)..." -ForegroundColor Yellow
|
||||
antlr4 -v 4.9.3 -Dlanguage=Python3 -visitor -o ./legacy MathExpr.g4
|
||||
|
||||
Write-Host "Compiling modern version (ANTLR 4.13.2)..." -ForegroundColor Yellow
|
||||
antlr4 -v 4.13.2 -Dlanguage=Python3 -visitor -o ./grammer MathExpr.g4
|
||||
}
|
||||
|
||||
Write-Host ""
|
||||
Write-Host "===================================================" -ForegroundColor Cyan
|
||||
@@ -19,12 +25,107 @@ if (-not (Test-Path $g4Path)) {
|
||||
exit 1
|
||||
}
|
||||
|
||||
# 1. Načtení a očištění gramatiky od komentářů
|
||||
$content = [System.IO.File]::ReadAllText($g4Path, [System.Text.Encoding]::UTF8)
|
||||
$content = $content -replace '//.*', ''
|
||||
$rawContent = [System.IO.File]::ReadAllText($g4Path, [System.Text.Encoding]::UTF8)
|
||||
$content = $rawContent -replace '//.*', ''
|
||||
$content = $content -replace '/\*[\s\S]*?\*/', ''
|
||||
|
||||
# 2. Vytažení všech alfabetických řetězců v apostrofech
|
||||
function Get-LexerNames([string]$grammarText) {
|
||||
$map = @{}
|
||||
foreach ($line in ($grammarText -split "`r?`n")) {
|
||||
$t = $line.Trim()
|
||||
if ($t -notmatch '^([A-Z][A-Z0-9_]*)\s*:\s*(.+);\s*$') { continue }
|
||||
$token = $matches[1]
|
||||
$rhs = $matches[2]
|
||||
$names = @(
|
||||
[regex]::Matches($rhs, "'([^']*)'") | ForEach-Object { $_.Groups[1].Value.ToLower() }
|
||||
) | Sort-Object -Unique
|
||||
if ($names.Count -gt 0) {
|
||||
$map[$token] = $names
|
||||
}
|
||||
}
|
||||
return $map
|
||||
}
|
||||
|
||||
function Get-ArgBounds([string]$inner) {
|
||||
$inner = $inner.Trim()
|
||||
if ([string]::IsNullOrWhiteSpace($inner)) {
|
||||
return @{ min = 0; max = 0 }
|
||||
}
|
||||
|
||||
$exprCount = ([regex]::Matches($inner, '\b(expr|indexExpr)\b')).Count
|
||||
$optExpr = 0
|
||||
foreach ($g in [regex]::Matches($inner, '\([^()]*\)\?')) {
|
||||
$optExpr += ([regex]::Matches($g.Value, '\b(expr|indexExpr)\b')).Count
|
||||
}
|
||||
|
||||
$hasStar = $inner -match '\(COMMA (expr|indexExpr)\)\*'
|
||||
$hasPlus = $inner -match '\(COMMA (expr|indexExpr)\)\+'
|
||||
|
||||
$min = $exprCount - $optExpr
|
||||
if ($hasStar) {
|
||||
$min = [Math]::Max(1, $exprCount - 1 - $optExpr)
|
||||
return @{ min = $min; max = $null }
|
||||
}
|
||||
if ($hasPlus) {
|
||||
$min = [Math]::Max(1, $exprCount - $optExpr)
|
||||
return @{ min = $min; max = $null }
|
||||
}
|
||||
|
||||
return @{ min = $min; max = $exprCount }
|
||||
}
|
||||
|
||||
function New-Snippet([string]$name) {
|
||||
return "${name}()"
|
||||
}
|
||||
|
||||
function Add-FunctionRuleLine([hashtable]$meta, [hashtable]$lexerMap, [string]$line) {
|
||||
$clean = (($line -split '\s+#')[0]).Trim().TrimEnd(';')
|
||||
if ($clean -notmatch 'LPAREN') { return }
|
||||
if ($clean -notmatch '(?:^\s*\|\s*)?(\w+)\s+LPAREN\s*(.*?)\s+RPAREN\s*$') { return }
|
||||
|
||||
$token = $matches[1]
|
||||
$inner = $matches[2].Trim()
|
||||
$bounds = Get-ArgBounds $inner
|
||||
$names = $lexerMap[$token]
|
||||
if (-not $names) { return }
|
||||
|
||||
foreach ($fn in $names) {
|
||||
$entry = @{
|
||||
minArgs = $bounds.min
|
||||
snippet = (New-Snippet $fn)
|
||||
}
|
||||
if ($null -eq $bounds.max) {
|
||||
$entry.maxArgs = $null
|
||||
} else {
|
||||
$entry.maxArgs = $bounds.max
|
||||
}
|
||||
$meta[$fn] = $entry
|
||||
}
|
||||
}
|
||||
|
||||
function Get-FunctionMeta([string]$grammarText, [hashtable]$lexerMap) {
|
||||
$meta = @{}
|
||||
$inFunc = $false
|
||||
|
||||
foreach ($line in ($grammarText -split "`r?`n")) {
|
||||
if ($line -match '^\s*//\s*LEXER') { $inFunc = $false }
|
||||
if ($line -match '^\s*(func0|func1|func2|func3|func4|func5|funcN|funcNoise)\s*:\s*(.*)$') {
|
||||
$inFunc = $true
|
||||
$inline = $matches[2].Trim()
|
||||
if ($inline -and $inline -match 'LPAREN') {
|
||||
Add-FunctionRuleLine $meta $lexerMap $inline
|
||||
}
|
||||
continue
|
||||
}
|
||||
if (-not $inFunc) { continue }
|
||||
|
||||
Add-FunctionRuleLine $meta $lexerMap $line
|
||||
}
|
||||
|
||||
return $meta
|
||||
}
|
||||
|
||||
# 1. Extract quoted symbols for keyword/function lists
|
||||
$matches = [regex]::Matches($content, "'([a-zA-Z_][a-zA-Z0-9_]*)'")
|
||||
$allSymbols = @()
|
||||
foreach ($m in $matches) {
|
||||
@@ -32,51 +133,92 @@ foreach ($m in $matches) {
|
||||
}
|
||||
$allSymbols = $allSymbols | Sort-Object -Unique
|
||||
|
||||
# 3. Definice pevných množin
|
||||
# 2. Fixed sets
|
||||
$keywords = @('if', 'else', 'while', 'for', 'in', 'break', 'continue', 'return', 'none', 'None', 'null', 'NULL') | Sort-Object -Unique
|
||||
$constants = @('pi', 'PI', 'e', 'E') | Sort-Object -Unique
|
||||
|
||||
# Vše ostatní, co jsou slova a nejsou klíčová slova ani konstanty, jsou funkce
|
||||
$functions = @()
|
||||
foreach ($sym in $allSymbols) {
|
||||
if ($sym -notin $keywords -and $sym -notin $constants) {
|
||||
$functions += $sym
|
||||
$functions += $sym.ToLower()
|
||||
}
|
||||
}
|
||||
$functions = $functions | Sort-Object -Unique
|
||||
|
||||
# 4. Formátování a zápis do PYTHON souboru (do kořene/aktuální složky vedle .g4)
|
||||
# 3. Function metadata from grammar rules
|
||||
$lexerMap = Get-LexerNames $content
|
||||
$functionMeta = Get-FunctionMeta $content $lexerMap
|
||||
|
||||
# Ensure every listed function has meta (fallback: variadic unknown)
|
||||
foreach ($fn in $functions) {
|
||||
if (-not $functionMeta.ContainsKey($fn)) {
|
||||
$functionMeta[$fn] = @{
|
||||
minArgs = 1
|
||||
maxArgs = $null
|
||||
snippet = (New-Snippet $fn)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$sortedMetaKeys = $functionMeta.Keys | Sort-Object
|
||||
|
||||
# 4. Python export
|
||||
$pyMetaLines = @()
|
||||
foreach ($key in $sortedMetaKeys) {
|
||||
$m = $functionMeta[$key]
|
||||
$maxPart = if ($null -eq $m.maxArgs) { "None" } else { [string]$m.maxArgs }
|
||||
$pyMetaLines += " '$key': {'min_args': $($m.minArgs), 'max_args': $maxPart, 'snippet': '$($m.snippet)'},"
|
||||
}
|
||||
|
||||
$pyPath = "inbuilt_symbols.py"
|
||||
$pyContent = @(
|
||||
"# Generated automatically by compile.ps1. Do not edit.",
|
||||
"INBUILT_KEYWORDS = {" + (($keywords | foreach { "'$_'" }) -join ", ") + "}",
|
||||
"INBUILT_CONSTANTS = {" + (($constants | foreach { "'$_'" }) -join ", ") + "}",
|
||||
"INBUILT_FUNCTIONS = {" + (($functions | foreach { "'$_'" }) -join ", ") + "}"
|
||||
"INBUILT_KEYWORDS = {" + (($keywords | ForEach-Object { "'$_'" }) -join ", ") + "}",
|
||||
"INBUILT_CONSTANTS = {" + (($constants | ForEach-Object { "'$_'" }) -join ", ") + "}",
|
||||
"INBUILT_FUNCTIONS = {" + (($functions | ForEach-Object { "'$_'" }) -join ", ") + "}",
|
||||
"",
|
||||
"INBUILT_FUNCTION_META = {",
|
||||
($pyMetaLines -join [Environment]::NewLine),
|
||||
"}"
|
||||
) -join [Environment]::NewLine
|
||||
|
||||
[System.IO.File]::WriteAllText($pyPath, $pyContent, [System.Text.Encoding]::UTF8)
|
||||
Write-Host "-> Exported Python symbols to root: $pyPath" -ForegroundColor Green
|
||||
|
||||
# 5. Formátování a zápis do JAVASCRIPT souboru (odskok do složky web)
|
||||
# Pokud máš složku web hned vedle .g4, změň '..\web' na 'web'
|
||||
$jsDir = "..\..\web"
|
||||
# 5. JavaScript export
|
||||
$jsDir = "..\..\web"
|
||||
if (-not (Test-Path $jsDir)) {
|
||||
New-Item -ItemType Directory -Force -Path $jsDir | Out-Null
|
||||
}
|
||||
$jsPath = Join-Path $jsDir "inbuilt_symbols.js"
|
||||
|
||||
$jsMetaLines = @()
|
||||
foreach ($key in $sortedMetaKeys) {
|
||||
$m = $functionMeta[$key]
|
||||
if ($null -eq $m.maxArgs) {
|
||||
$jsMetaLines += " $key`: { minArgs: $($m.minArgs), maxArgs: null, snippet: `"$($m.snippet)`" },"
|
||||
} else {
|
||||
$jsMetaLines += " $key`: { minArgs: $($m.minArgs), maxArgs: $($m.maxArgs), snippet: `"$($m.snippet)`" },"
|
||||
}
|
||||
}
|
||||
|
||||
$jsContent = @(
|
||||
"// Generated automatically by compile.ps1. Do not edit.",
|
||||
"",
|
||||
"export const KEYWORDS = new Set([" + (($keywords | foreach { "`"$_`"" }) -join ", ") + "]);",
|
||||
"export const KEYWORDS = new Set([" + (($keywords | ForEach-Object { "`"$_`"" }) -join ", ") + "]);",
|
||||
"",
|
||||
"export const CONSTANTS = new Set([" + (($constants | foreach { "`"$_`"" }) -join ", ") + "]);",
|
||||
"export const CONSTANTS = new Set([" + (($constants | ForEach-Object { "`"$_`"" }) -join ", ") + "]);",
|
||||
"",
|
||||
"export const FUNCTIONS = new Set([" + (($functions | foreach { "`"$_`"" }) -join ", ") + "]);"
|
||||
"export const FUNCTIONS = new Set([" + (($functions | ForEach-Object { "`"$_`"" }) -join ", ") + "]);",
|
||||
"",
|
||||
"export const FUNCTION_META = {",
|
||||
($jsMetaLines -join [Environment]::NewLine),
|
||||
"};"
|
||||
) -join [Environment]::NewLine
|
||||
|
||||
[System.IO.File]::WriteAllText($jsPath, $jsContent, [System.Text.Encoding]::UTF8)
|
||||
Write-Host "-> Exported JS symbols to: $jsPath" -ForegroundColor Green
|
||||
Write-Host "-> Function metadata entries: $($sortedMetaKeys.Count)" -ForegroundColor Green
|
||||
|
||||
Write-Host ""
|
||||
Write-Host "===================================================" -ForegroundColor Cyan
|
||||
|
||||
@@ -7,4 +7,241 @@ INBUILT_CONSTANTS = {
|
||||
}
|
||||
INBUILT_FUNCTIONS = {
|
||||
'abs', 'acos', 'acosh', 'all', 'angle', 'any', 'append', 'argmax', 'argmin', 'argsort', 'asin', 'asinh', 'atan', 'atan2', 'atanh', 'band', 'batch_shuffle', 'bitcount', 'bitwise_and', 'bitwise_not', 'bitwise_or', 'bitwise_xor', 'blur', 'bnot', 'bor', 'botk', 'botk_ind', 'botk_indices', 'bxor', 'cat', 'ceil', 'cellular', 'cellular_noise', 'cielab_to_rgb', 'clamp', 'cnt', 'concat', 'concatenate', 'conv', 'convolution', 'corr', 'correlation', 'cos', 'cosh', 'cosine_similarity', 'cossim', 'count', 'cov', 'crop', 'cross', 'cubic', 'cubic_ease', 'cumprod', 'cumsum', 'dilate', 'dist', 'distance', 'domain_warp', 'domain_warp_noise', 'dot', 'edge', 'elastic', 'elastic_ease', 'entropy', 'erf', 'erfinv', 'erode', 'exp', 'ezconv', 'ezconvolution', 'fft', 'find', 'flatten', 'flip', 'float', 'floor', 'flow_ang', 'flow_angle', 'flow_apply', 'flow_mag', 'flow_magnitude', 'flow_to_image', 'fract', 'gamma', 'gaussian', 'gelu', 'get_value', 'hist', 'histogram', 'hsv_to_rgb', 'ifft', 'int', 'int_to_rgb', 'interpolate_area', 'interpolate_linear', 'interpolate_nearest', 'interpolate_nearest_exact', 'join', 'length', 'lerp', 'linspace', 'ln', 'log', 'logspace', 'lower', 'map', 'matmul', 'mean', 'median', 'mode', 'moment', 'morph_close', 'morph_open', 'motion_mask', 'nan_to_num', 'noise', 'now', 'nvl', 'oklab_to_rgb', 'overlay', 'pad', 'percentile', 'perlin', 'perlin_noise', 'perm', 'permute', 'pinv', 'plasma', 'plasma_noise', 'popcnt', 'popcount', 'pow', 'prcnt', 'print', 'print_shape', 'pshp', 'quantile', 'quartil', 'quartile', 'rand', 'randb', 'randbeta', 'randc', 'rande', 'randg', 'randgumbel', 'randchi2', 'randl', 'randln', 'randn', 'random_bernoulli', 'random_beta', 'random_cauchy', 'random_exponential', 'random_gamma', 'random_gumbel', 'random_chi2', 'random_laplace', 'random_log_normal', 'random_normal', 'random_poisson', 'random_studentt', 'random_uniform', 'random_weibull', 'randp', 'randt', 'randu', 'randw', 'range', 'relu', 'remap', 'replace', 'reshape', 'rgb_to_cielab', 'rgb_to_hsv', 'rgb_to_int', 'rgb_to_oklab', 'ridged', 'ridged_noise', 'rife', 'roll', 'round', 'rshp', 'select', 'shape', 'shuffle', 'sigm', 'sign', 'sin', 'sine', 'sine_ease', 'sinh', 'smax', 'smin', 'smootherstep', 'smoothstep', 'snorm', 'softmax', 'softmin', 'softplus', 'sort', 'split', 'sqrt', 'stack_clear', 'stack_get', 'stack_has', 'stack_pop', 'stack_push', 'std', 'step', 'substr', 'substring', 'sum', 'swap', 'tan', 'tanh', 'tensor', 'text_image', 'timestamp', 'tmax', 'tmin', 'tnorm', 'topk', 'topk_ind', 'topk_indices', 'trim', 'turbulence', 'unique', 'upper', 'var', 'voronoi', 'voronoi_noise', 'where', 'worley'
|
||||
}
|
||||
|
||||
INBUILT_FUNCTION_META = {
|
||||
'abs': {'min_args': 1, 'max_args': 1, 'snippet': 'abs()'},
|
||||
'acos': {'min_args': 1, 'max_args': 1, 'snippet': 'acos()'},
|
||||
'acosh': {'min_args': 1, 'max_args': 1, 'snippet': 'acosh()'},
|
||||
'all': {'min_args': 1, 'max_args': 1, 'snippet': 'all()'},
|
||||
'angle': {'min_args': 1, 'max_args': 1, 'snippet': 'angle()'},
|
||||
'any': {'min_args': 1, 'max_args': 1, 'snippet': 'any()'},
|
||||
'append': {'min_args': 2, 'max_args': 2, 'snippet': 'append()'},
|
||||
'argmax': {'min_args': 1, 'max_args': 1, 'snippet': 'argmax()'},
|
||||
'argmin': {'min_args': 1, 'max_args': 1, 'snippet': 'argmin()'},
|
||||
'argsort': {'min_args': 1, 'max_args': 2, 'snippet': 'argsort()'},
|
||||
'asin': {'min_args': 1, 'max_args': 1, 'snippet': 'asin()'},
|
||||
'asinh': {'min_args': 1, 'max_args': 1, 'snippet': 'asinh()'},
|
||||
'atan': {'min_args': 1, 'max_args': 1, 'snippet': 'atan()'},
|
||||
'atan2': {'min_args': 2, 'max_args': 2, 'snippet': 'atan2()'},
|
||||
'atanh': {'min_args': 1, 'max_args': 1, 'snippet': 'atanh()'},
|
||||
'band': {'min_args': 2, 'max_args': 2, 'snippet': 'band()'},
|
||||
'batch_shuffle': {'min_args': 2, 'max_args': 2, 'snippet': 'batch_shuffle()'},
|
||||
'bitcount': {'min_args': 1, 'max_args': 1, 'snippet': 'bitcount()'},
|
||||
'bitwise_and': {'min_args': 2, 'max_args': 2, 'snippet': 'bitwise_and()'},
|
||||
'bitwise_not': {'min_args': 1, 'max_args': 1, 'snippet': 'bitwise_not()'},
|
||||
'bitwise_or': {'min_args': 2, 'max_args': 2, 'snippet': 'bitwise_or()'},
|
||||
'bitwise_xor': {'min_args': 2, 'max_args': 2, 'snippet': 'bitwise_xor()'},
|
||||
'blur': {'min_args': 2, 'max_args': 3, 'snippet': 'blur()'},
|
||||
'bnot': {'min_args': 1, 'max_args': 1, 'snippet': 'bnot()'},
|
||||
'bor': {'min_args': 2, 'max_args': 2, 'snippet': 'bor()'},
|
||||
'botk': {'min_args': 2, 'max_args': 2, 'snippet': 'botk()'},
|
||||
'botk_ind': {'min_args': 2, 'max_args': 2, 'snippet': 'botk_ind()'},
|
||||
'botk_indices': {'min_args': 2, 'max_args': 2, 'snippet': 'botk_indices()'},
|
||||
'bxor': {'min_args': 2, 'max_args': 2, 'snippet': 'bxor()'},
|
||||
'cat': {'min_args': 2, 'max_args': None, 'snippet': 'cat()'},
|
||||
'ceil': {'min_args': 1, 'max_args': 1, 'snippet': 'ceil()'},
|
||||
'cellular': {'min_args': 2, 'max_args': 5, 'snippet': 'cellular()'},
|
||||
'cellular_noise': {'min_args': 2, 'max_args': 5, 'snippet': 'cellular_noise()'},
|
||||
'cielab_to_rgb': {'min_args': 1, 'max_args': 3, 'snippet': 'cielab_to_rgb()'},
|
||||
'clamp': {'min_args': 3, 'max_args': 3, 'snippet': 'clamp()'},
|
||||
'cnt': {'min_args': 1, 'max_args': 1, 'snippet': 'cnt()'},
|
||||
'concat': {'min_args': 2, 'max_args': None, 'snippet': 'concat()'},
|
||||
'concatenate': {'min_args': 2, 'max_args': None, 'snippet': 'concatenate()'},
|
||||
'conv': {'min_args': 2, 'max_args': None, 'snippet': 'conv()'},
|
||||
'convolution': {'min_args': 2, 'max_args': None, 'snippet': 'convolution()'},
|
||||
'corr': {'min_args': 2, 'max_args': 2, 'snippet': 'corr()'},
|
||||
'correlation': {'min_args': 2, 'max_args': 2, 'snippet': 'correlation()'},
|
||||
'cos': {'min_args': 1, 'max_args': 1, 'snippet': 'cos()'},
|
||||
'cosh': {'min_args': 1, 'max_args': 1, 'snippet': 'cosh()'},
|
||||
'cosine_similarity': {'min_args': 2, 'max_args': 2, 'snippet': 'cosine_similarity()'},
|
||||
'cossim': {'min_args': 2, 'max_args': 2, 'snippet': 'cossim()'},
|
||||
'count': {'min_args': 1, 'max_args': 1, 'snippet': 'count()'},
|
||||
'cov': {'min_args': 2, 'max_args': 2, 'snippet': 'cov()'},
|
||||
'crop': {'min_args': 3, 'max_args': 3, 'snippet': 'crop()'},
|
||||
'cross': {'min_args': 2, 'max_args': 2, 'snippet': 'cross()'},
|
||||
'cubic': {'min_args': 3, 'max_args': 3, 'snippet': 'cubic()'},
|
||||
'cubic_ease': {'min_args': 3, 'max_args': 3, 'snippet': 'cubic_ease()'},
|
||||
'cumprod': {'min_args': 1, 'max_args': 1, 'snippet': 'cumprod()'},
|
||||
'cumsum': {'min_args': 1, 'max_args': 1, 'snippet': 'cumsum()'},
|
||||
'dilate': {'min_args': 1, 'max_args': 2, 'snippet': 'dilate()'},
|
||||
'dist': {'min_args': 4, 'max_args': 4, 'snippet': 'dist()'},
|
||||
'distance': {'min_args': 4, 'max_args': 4, 'snippet': 'distance()'},
|
||||
'domain_warp': {'min_args': 4, 'max_args': 8, 'snippet': 'domain_warp()'},
|
||||
'domain_warp_noise': {'min_args': 4, 'max_args': 8, 'snippet': 'domain_warp_noise()'},
|
||||
'dot': {'min_args': 2, 'max_args': 2, 'snippet': 'dot()'},
|
||||
'edge': {'min_args': 1, 'max_args': 2, 'snippet': 'edge()'},
|
||||
'elastic': {'min_args': 3, 'max_args': 3, 'snippet': 'elastic()'},
|
||||
'elastic_ease': {'min_args': 3, 'max_args': 3, 'snippet': 'elastic_ease()'},
|
||||
'entropy': {'min_args': 1, 'max_args': 1, 'snippet': 'entropy()'},
|
||||
'erf': {'min_args': 1, 'max_args': 1, 'snippet': 'erf()'},
|
||||
'erfinv': {'min_args': 1, 'max_args': 1, 'snippet': 'erfinv()'},
|
||||
'erode': {'min_args': 1, 'max_args': 2, 'snippet': 'erode()'},
|
||||
'exp': {'min_args': 1, 'max_args': 1, 'snippet': 'exp()'},
|
||||
'ezconv': {'min_args': 2, 'max_args': None, 'snippet': 'ezconv()'},
|
||||
'ezconvolution': {'min_args': 2, 'max_args': None, 'snippet': 'ezconvolution()'},
|
||||
'fft': {'min_args': 1, 'max_args': 1, 'snippet': 'fft()'},
|
||||
'find': {'min_args': 2, 'max_args': 2, 'snippet': 'find()'},
|
||||
'flatten': {'min_args': 1, 'max_args': 1, 'snippet': 'flatten()'},
|
||||
'flip': {'min_args': 2, 'max_args': 2, 'snippet': 'flip()'},
|
||||
'float': {'min_args': 1, 'max_args': 1, 'snippet': 'float()'},
|
||||
'floor': {'min_args': 1, 'max_args': 1, 'snippet': 'floor()'},
|
||||
'flow_ang': {'min_args': 1, 'max_args': 1, 'snippet': 'flow_ang()'},
|
||||
'flow_angle': {'min_args': 1, 'max_args': 1, 'snippet': 'flow_angle()'},
|
||||
'flow_apply': {'min_args': 2, 'max_args': 2, 'snippet': 'flow_apply()'},
|
||||
'flow_mag': {'min_args': 1, 'max_args': 1, 'snippet': 'flow_mag()'},
|
||||
'flow_magnitude': {'min_args': 1, 'max_args': 1, 'snippet': 'flow_magnitude()'},
|
||||
'flow_to_image': {'min_args': 1, 'max_args': 1, 'snippet': 'flow_to_image()'},
|
||||
'fract': {'min_args': 1, 'max_args': 1, 'snippet': 'fract()'},
|
||||
'gamma': {'min_args': 1, 'max_args': 1, 'snippet': 'gamma()'},
|
||||
'gaussian': {'min_args': 2, 'max_args': 3, 'snippet': 'gaussian()'},
|
||||
'gelu': {'min_args': 1, 'max_args': 1, 'snippet': 'gelu()'},
|
||||
'get_value': {'min_args': 2, 'max_args': 2, 'snippet': 'get_value()'},
|
||||
'hist': {'min_args': 4, 'max_args': 4, 'snippet': 'hist()'},
|
||||
'histogram': {'min_args': 4, 'max_args': 4, 'snippet': 'histogram()'},
|
||||
'hsv_to_rgb': {'min_args': 1, 'max_args': 4, 'snippet': 'hsv_to_rgb()'},
|
||||
'ifft': {'min_args': 1, 'max_args': 2, 'snippet': 'ifft()'},
|
||||
'int': {'min_args': 1, 'max_args': 1, 'snippet': 'int()'},
|
||||
'int_to_rgb': {'min_args': 1, 'max_args': 1, 'snippet': 'int_to_rgb()'},
|
||||
'interpolate_area': {'min_args': 2, 'max_args': 2, 'snippet': 'interpolate_area()'},
|
||||
'interpolate_linear': {'min_args': 2, 'max_args': 2, 'snippet': 'interpolate_linear()'},
|
||||
'interpolate_nearest': {'min_args': 2, 'max_args': 2, 'snippet': 'interpolate_nearest()'},
|
||||
'interpolate_nearest_exact': {'min_args': 2, 'max_args': 2, 'snippet': 'interpolate_nearest_exact()'},
|
||||
'join': {'min_args': 1, 'max_args': 2, 'snippet': 'join()'},
|
||||
'length': {'min_args': 1, 'max_args': 1, 'snippet': 'length()'},
|
||||
'lerp': {'min_args': 3, 'max_args': 3, 'snippet': 'lerp()'},
|
||||
'linspace': {'min_args': 3, 'max_args': 3, 'snippet': 'linspace()'},
|
||||
'ln': {'min_args': 1, 'max_args': 1, 'snippet': 'ln()'},
|
||||
'log': {'min_args': 1, 'max_args': 1, 'snippet': 'log()'},
|
||||
'logspace': {'min_args': 4, 'max_args': 4, 'snippet': 'logspace()'},
|
||||
'lower': {'min_args': 1, 'max_args': 1, 'snippet': 'lower()'},
|
||||
'map': {'min_args': 2, 'max_args': None, 'snippet': 'map()'},
|
||||
'matmul': {'min_args': 2, 'max_args': 2, 'snippet': 'matmul()'},
|
||||
'mean': {'min_args': 1, 'max_args': 1, 'snippet': 'mean()'},
|
||||
'median': {'min_args': 1, 'max_args': 1, 'snippet': 'median()'},
|
||||
'mode': {'min_args': 1, 'max_args': 1, 'snippet': 'mode()'},
|
||||
'moment': {'min_args': 3, 'max_args': 3, 'snippet': 'moment()'},
|
||||
'morph_close': {'min_args': 1, 'max_args': 2, 'snippet': 'morph_close()'},
|
||||
'morph_open': {'min_args': 1, 'max_args': 2, 'snippet': 'morph_open()'},
|
||||
'motion_mask': {'min_args': 1, 'max_args': 1, 'snippet': 'motion_mask()'},
|
||||
'nan_to_num': {'min_args': 4, 'max_args': 4, 'snippet': 'nan_to_num()'},
|
||||
'noise': {'min_args': 1, 'max_args': 2, 'snippet': 'noise()'},
|
||||
'now': {'min_args': 0, 'max_args': 0, 'snippet': 'now()'},
|
||||
'nvl': {'min_args': 4, 'max_args': 4, 'snippet': 'nvl()'},
|
||||
'oklab_to_rgb': {'min_args': 1, 'max_args': 3, 'snippet': 'oklab_to_rgb()'},
|
||||
'overlay': {'min_args': 3, 'max_args': 4, 'snippet': 'overlay()'},
|
||||
'pad': {'min_args': 2, 'max_args': 2, 'snippet': 'pad()'},
|
||||
'percentile': {'min_args': 2, 'max_args': 2, 'snippet': 'percentile()'},
|
||||
'perlin': {'min_args': 2, 'max_args': 5, 'snippet': 'perlin()'},
|
||||
'perlin_noise': {'min_args': 2, 'max_args': 5, 'snippet': 'perlin_noise()'},
|
||||
'perm': {'min_args': 2, 'max_args': 2, 'snippet': 'perm()'},
|
||||
'permute': {'min_args': 2, 'max_args': 2, 'snippet': 'permute()'},
|
||||
'pinv': {'min_args': 1, 'max_args': 1, 'snippet': 'pinv()'},
|
||||
'plasma': {'min_args': 2, 'max_args': 5, 'snippet': 'plasma()'},
|
||||
'plasma_noise': {'min_args': 2, 'max_args': 5, 'snippet': 'plasma_noise()'},
|
||||
'popcnt': {'min_args': 1, 'max_args': 1, 'snippet': 'popcnt()'},
|
||||
'popcount': {'min_args': 1, 'max_args': 1, 'snippet': 'popcount()'},
|
||||
'pow': {'min_args': 2, 'max_args': 2, 'snippet': 'pow()'},
|
||||
'prcnt': {'min_args': 2, 'max_args': 2, 'snippet': 'prcnt()'},
|
||||
'print': {'min_args': 1, 'max_args': 1, 'snippet': 'print()'},
|
||||
'print_shape': {'min_args': 1, 'max_args': 1, 'snippet': 'print_shape()'},
|
||||
'pshp': {'min_args': 1, 'max_args': 1, 'snippet': 'pshp()'},
|
||||
'quantile': {'min_args': 2, 'max_args': 2, 'snippet': 'quantile()'},
|
||||
'quartil': {'min_args': 2, 'max_args': 2, 'snippet': 'quartil()'},
|
||||
'quartile': {'min_args': 2, 'max_args': 2, 'snippet': 'quartile()'},
|
||||
'rand': {'min_args': 1, 'max_args': 2, 'snippet': 'rand()'},
|
||||
'randb': {'min_args': 2, 'max_args': 3, 'snippet': 'randb()'},
|
||||
'randbeta': {'min_args': 3, 'max_args': 4, 'snippet': 'randbeta()'},
|
||||
'randc': {'min_args': 3, 'max_args': 4, 'snippet': 'randc()'},
|
||||
'rande': {'min_args': 2, 'max_args': 3, 'snippet': 'rande()'},
|
||||
'randg': {'min_args': 3, 'max_args': 4, 'snippet': 'randg()'},
|
||||
'randgumbel': {'min_args': 3, 'max_args': 4, 'snippet': 'randgumbel()'},
|
||||
'randchi2': {'min_args': 2, 'max_args': 3, 'snippet': 'randchi2()'},
|
||||
'randl': {'min_args': 3, 'max_args': 4, 'snippet': 'randl()'},
|
||||
'randln': {'min_args': 3, 'max_args': 4, 'snippet': 'randln()'},
|
||||
'randn': {'min_args': 1, 'max_args': 2, 'snippet': 'randn()'},
|
||||
'random_bernoulli': {'min_args': 2, 'max_args': 3, 'snippet': 'random_bernoulli()'},
|
||||
'random_beta': {'min_args': 3, 'max_args': 4, 'snippet': 'random_beta()'},
|
||||
'random_cauchy': {'min_args': 3, 'max_args': 4, 'snippet': 'random_cauchy()'},
|
||||
'random_exponential': {'min_args': 2, 'max_args': 3, 'snippet': 'random_exponential()'},
|
||||
'random_gamma': {'min_args': 3, 'max_args': 4, 'snippet': 'random_gamma()'},
|
||||
'random_gumbel': {'min_args': 3, 'max_args': 4, 'snippet': 'random_gumbel()'},
|
||||
'random_chi2': {'min_args': 2, 'max_args': 3, 'snippet': 'random_chi2()'},
|
||||
'random_laplace': {'min_args': 3, 'max_args': 4, 'snippet': 'random_laplace()'},
|
||||
'random_log_normal': {'min_args': 3, 'max_args': 4, 'snippet': 'random_log_normal()'},
|
||||
'random_normal': {'min_args': 1, 'max_args': 2, 'snippet': 'random_normal()'},
|
||||
'random_poisson': {'min_args': 2, 'max_args': 3, 'snippet': 'random_poisson()'},
|
||||
'random_studentt': {'min_args': 2, 'max_args': 3, 'snippet': 'random_studentt()'},
|
||||
'random_uniform': {'min_args': 1, 'max_args': 2, 'snippet': 'random_uniform()'},
|
||||
'random_weibull': {'min_args': 3, 'max_args': 4, 'snippet': 'random_weibull()'},
|
||||
'randp': {'min_args': 2, 'max_args': 3, 'snippet': 'randp()'},
|
||||
'randt': {'min_args': 2, 'max_args': 3, 'snippet': 'randt()'},
|
||||
'randu': {'min_args': 1, 'max_args': 2, 'snippet': 'randu()'},
|
||||
'randw': {'min_args': 3, 'max_args': 4, 'snippet': 'randw()'},
|
||||
'range': {'min_args': 3, 'max_args': 3, 'snippet': 'range()'},
|
||||
'relu': {'min_args': 1, 'max_args': None, 'snippet': 'relu()'},
|
||||
'remap': {'min_args': 5, 'max_args': 5, 'snippet': 'remap()'},
|
||||
'replace': {'min_args': 3, 'max_args': 3, 'snippet': 'replace()'},
|
||||
'reshape': {'min_args': 2, 'max_args': 2, 'snippet': 'reshape()'},
|
||||
'rgb_to_cielab': {'min_args': 1, 'max_args': 3, 'snippet': 'rgb_to_cielab()'},
|
||||
'rgb_to_hsv': {'min_args': 1, 'max_args': 4, 'snippet': 'rgb_to_hsv()'},
|
||||
'rgb_to_int': {'min_args': 1, 'max_args': 3, 'snippet': 'rgb_to_int()'},
|
||||
'rgb_to_oklab': {'min_args': 1, 'max_args': 3, 'snippet': 'rgb_to_oklab()'},
|
||||
'ridged': {'min_args': 2, 'max_args': 5, 'snippet': 'ridged()'},
|
||||
'ridged_noise': {'min_args': 2, 'max_args': 5, 'snippet': 'ridged_noise()'},
|
||||
'rife': {'min_args': 4, 'max_args': 5, 'snippet': 'rife()'},
|
||||
'roll': {'min_args': 2, 'max_args': 3, 'snippet': 'roll()'},
|
||||
'round': {'min_args': 1, 'max_args': 1, 'snippet': 'round()'},
|
||||
'rshp': {'min_args': 2, 'max_args': 2, 'snippet': 'rshp()'},
|
||||
'select': {'min_args': 2, 'max_args': 2, 'snippet': 'select()'},
|
||||
'shape': {'min_args': 1, 'max_args': 1, 'snippet': 'shape()'},
|
||||
'shuffle': {'min_args': 2, 'max_args': 2, 'snippet': 'shuffle()'},
|
||||
'sigm': {'min_args': 1, 'max_args': 1, 'snippet': 'sigm()'},
|
||||
'sign': {'min_args': 1, 'max_args': 1, 'snippet': 'sign()'},
|
||||
'sin': {'min_args': 1, 'max_args': 1, 'snippet': 'sin()'},
|
||||
'sine': {'min_args': 3, 'max_args': 3, 'snippet': 'sine()'},
|
||||
'sine_ease': {'min_args': 3, 'max_args': 3, 'snippet': 'sine_ease()'},
|
||||
'sinh': {'min_args': 1, 'max_args': 1, 'snippet': 'sinh()'},
|
||||
'smax': {'min_args': 1, 'max_args': None, 'snippet': 'smax()'},
|
||||
'smin': {'min_args': 1, 'max_args': None, 'snippet': 'smin()'},
|
||||
'smootherstep': {'min_args': 3, 'max_args': 3, 'snippet': 'smootherstep()'},
|
||||
'smoothstep': {'min_args': 3, 'max_args': 3, 'snippet': 'smoothstep()'},
|
||||
'snorm': {'min_args': 1, 'max_args': 1, 'snippet': 'snorm()'},
|
||||
'softmax': {'min_args': 1, 'max_args': 2, 'snippet': 'softmax()'},
|
||||
'softmin': {'min_args': 1, 'max_args': 2, 'snippet': 'softmin()'},
|
||||
'softplus': {'min_args': 1, 'max_args': 1, 'snippet': 'softplus()'},
|
||||
'sort': {'min_args': 1, 'max_args': 1, 'snippet': 'sort()'},
|
||||
'split': {'min_args': 1, 'max_args': 2, 'snippet': 'split()'},
|
||||
'sqrt': {'min_args': 1, 'max_args': 1, 'snippet': 'sqrt()'},
|
||||
'stack_clear': {'min_args': 1, 'max_args': 1, 'snippet': 'stack_clear()'},
|
||||
'stack_get': {'min_args': 1, 'max_args': 1, 'snippet': 'stack_get()'},
|
||||
'stack_has': {'min_args': 1, 'max_args': 1, 'snippet': 'stack_has()'},
|
||||
'stack_pop': {'min_args': 1, 'max_args': 1, 'snippet': 'stack_pop()'},
|
||||
'stack_push': {'min_args': 2, 'max_args': 2, 'snippet': 'stack_push()'},
|
||||
'std': {'min_args': 1, 'max_args': 1, 'snippet': 'std()'},
|
||||
'step': {'min_args': 2, 'max_args': 2, 'snippet': 'step()'},
|
||||
'substr': {'min_args': 2, 'max_args': 3, 'snippet': 'substr()'},
|
||||
'substring': {'min_args': 2, 'max_args': 3, 'snippet': 'substring()'},
|
||||
'sum': {'min_args': 1, 'max_args': 1, 'snippet': 'sum()'},
|
||||
'swap': {'min_args': 4, 'max_args': 4, 'snippet': 'swap()'},
|
||||
'tan': {'min_args': 1, 'max_args': 1, 'snippet': 'tan()'},
|
||||
'tanh': {'min_args': 1, 'max_args': 1, 'snippet': 'tanh()'},
|
||||
'tensor': {'min_args': 2, 'max_args': 3, 'snippet': 'tensor()'},
|
||||
'text_image': {'min_args': 3, 'max_args': 9, 'snippet': 'text_image()'},
|
||||
'timestamp': {'min_args': 0, 'max_args': 0, 'snippet': 'timestamp()'},
|
||||
'tmax': {'min_args': 2, 'max_args': 2, 'snippet': 'tmax()'},
|
||||
'tmin': {'min_args': 2, 'max_args': 2, 'snippet': 'tmin()'},
|
||||
'tnorm': {'min_args': 1, 'max_args': 1, 'snippet': 'tnorm()'},
|
||||
'topk': {'min_args': 2, 'max_args': 2, 'snippet': 'topk()'},
|
||||
'topk_ind': {'min_args': 2, 'max_args': 2, 'snippet': 'topk_ind()'},
|
||||
'topk_indices': {'min_args': 2, 'max_args': 2, 'snippet': 'topk_indices()'},
|
||||
'trim': {'min_args': 1, 'max_args': 1, 'snippet': 'trim()'},
|
||||
'turbulence': {'min_args': 2, 'max_args': 5, 'snippet': 'turbulence()'},
|
||||
'unique': {'min_args': 1, 'max_args': 1, 'snippet': 'unique()'},
|
||||
'upper': {'min_args': 1, 'max_args': 1, 'snippet': 'upper()'},
|
||||
'var': {'min_args': 1, 'max_args': 1, 'snippet': 'var()'},
|
||||
'voronoi': {'min_args': 2, 'max_args': 5, 'snippet': 'voronoi()'},
|
||||
'voronoi_noise': {'min_args': 2, 'max_args': 5, 'snippet': 'voronoi_noise()'},
|
||||
'where': {'min_args': 3, 'max_args': 3, 'snippet': 'where()'},
|
||||
'worley': {'min_args': 2, 'max_args': 5, 'snippet': 'worley()'},
|
||||
}
|
||||
+11
-33
@@ -1,6 +1,7 @@
|
||||
<template>
|
||||
<div
|
||||
class="mrmth-editor"
|
||||
data-mrmth-script-widget="vue"
|
||||
ref="wrapperRef"
|
||||
:style="editorStyle"
|
||||
>
|
||||
@@ -61,6 +62,8 @@
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref, computed, onMounted, onBeforeUnmount, nextTick, watch } from 'vue';
|
||||
import { KEYWORDS, CONSTANTS, FUNCTIONS } from './inbuilt_symbols.js';
|
||||
import { attachAutocomplete } from './autocomplete.js';
|
||||
|
||||
// Define model for value binding
|
||||
const modelValue = defineModel<string>({ default: '' });
|
||||
@@ -100,39 +103,6 @@ const escapeHtml = (value: string): string => {
|
||||
.replace(/'/g, ''');
|
||||
};
|
||||
|
||||
// Language constructs for tokenizing
|
||||
const KEYWORDS = new Set(['if', 'else', 'while', 'for', 'in', 'break', 'continue', 'return', 'none', 'None', 'null', 'NULL']);
|
||||
const CONSTANTS = new Set(['pi', 'PI', 'e', 'E']);
|
||||
const FUNCTIONS = new Set([
|
||||
'sin', 'cos', 'tan', 'asin', 'acos', 'atan', 'atan2', 'sinh', 'cosh', 'tanh', 'asinh', 'acosh', 'atanh',
|
||||
'abs', 'sqrt', 'ln', 'log', 'exp', 'smin', 'smax', 'tmin', 'tmax', 'tnorm', 'snorm', 'floor', 'ceil',
|
||||
'round', 'gamma', 'pow', 'sigm', 'clamp', 'fft', 'ifft', 'angle', 'print', 'print_shape', 'pshp', 'nvl',
|
||||
'nan_to_num', 'lerp', 'step', 'smoothstep', 'fract', 'relu', 'softplus', 'gelu', 'sign', 'map', 'ezconvolution',
|
||||
'ezconv', 'convolution', 'conv', 'swap', 'permute', 'perm', 'reshape', 'rshp', 'range', 'topk', 'botk', 'pinv',
|
||||
'sum', 'mean', 'std', 'var', 'quartile', 'quartil', 'percentile', 'prcnt', 'quantile', 'dot', 'moment', 'erf', 'erfinv', 'any',
|
||||
'all', 'edge', 'blur', 'gaussian', 'median', 'mode', 'cumsum', 'cumprod', 'topk_ind', 'topk_indices', 'botk_ind',
|
||||
'botk_indices', 'cubic_ease', 'cubic', 'elastic_ease', 'elastic', 'sine_ease', 'sine', 'smootherstep', 'dist',
|
||||
'distance', 'remap', 'cossim', 'cosine_similarity', 'count', 'cnt', 'length', 'flatten', 'append', 'get_value',
|
||||
'flow_apply', 'batch_shuffle', 'shuffle', 'motion_mask', 'flow_to_image', 'overlay', 'pad', 'cross', 'matmul', 'rife',
|
||||
'bnot', 'bitwise_not', 'bitcount', 'popcount', 'popcnt', 'shape', 'band', 'bitwise_and', 'bxor', 'bitwise_xor',
|
||||
'bor', 'bitwise_or', 'tensor', 'stack_push', 'stack_pop', 'stack_clear', 'stack_has', 'stack_get', 'timestamp', 'now',
|
||||
'sort', 'argsort', 'argmin', 'argmax', 'softmax', 'softmin', 'unique', 'flip', 'cov', 'corr', 'correlation', 'entropy',
|
||||
'crop', 'cat', 'concatenate', 'concat', 'float', 'int', 'linspace', 'logspace', 'roll', 'select',
|
||||
'noise', 'randn', 'random_normal', 'rand', 'randu', 'random_uniform', 'randc', 'random_cauchy', 'rande',
|
||||
'random_exponential', 'randln', 'random_log_normal', 'randb', 'random_bernoulli', 'randp', 'random_poisson', 'randg',
|
||||
'random_gamma', 'randbeta', 'random_beta', 'randl', 'random_laplace', 'randgumbel', 'random_gumbel', 'randw',
|
||||
'random_weibull', 'randchi2', 'random_chi2', 'randt', 'random_studentt', 'perlin', 'perlin_noise', 'cellular', 'voronoi',
|
||||
'worley', 'cellular_noise', 'voronoi_noise', 'plasma', 'turbulence', 'plasma_noise', 'ridged', 'ridged_noise',
|
||||
'domain_warp', 'domain_warp_noise',
|
||||
'upper', 'lower', 'split', 'join', 'substring', 'substr', 'find', 'trim', 'replace',
|
||||
'dilate', 'erode', 'morph_open', 'morph_close',
|
||||
'rgb_to_hsv', 'hsv_to_rgb',
|
||||
'rgb_to_oklab', 'oklab_to_rgb', 'rgb_to_cielab', 'cielab_to_rgb',
|
||||
'int_to_rgb', 'rgb_to_int',
|
||||
'where', 'histogram', 'hist', 'flow_mag', 'flow_magnitude', 'flow_ang', 'flow_angle',
|
||||
'interpolate_linear', 'interpolate_area', 'interpolate_nearest', 'interpolate_nearest_exact'
|
||||
]);
|
||||
|
||||
const BRACKET_PAIRS: Record<string, string> = { '(': ')', '[': ']', '{': '}' };
|
||||
const OPENING_BRACKETS = new Set(['(', '[', '{']);
|
||||
const CLOSING_BRACKETS = new Set([')', ']', '}']);
|
||||
@@ -464,6 +434,7 @@ const editorStyle = computed(() => {
|
||||
|
||||
// Setup observers
|
||||
let resizeObserver: ResizeObserver | null = null;
|
||||
let autocompleteController: { destroy: () => void } | null = null;
|
||||
|
||||
onMounted(() => {
|
||||
refresh();
|
||||
@@ -477,9 +448,16 @@ onMounted(() => {
|
||||
});
|
||||
resizeObserver.observe(editorContainerRef.value);
|
||||
}
|
||||
|
||||
nextTick(() => {
|
||||
if (textareaRef.value && editorContainerRef.value) {
|
||||
autocompleteController = attachAutocomplete(textareaRef.value, editorContainerRef.value);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
onBeforeUnmount(() => {
|
||||
autocompleteController?.destroy();
|
||||
if (resizeObserver) {
|
||||
resizeObserver.disconnect();
|
||||
}
|
||||
|
||||
@@ -0,0 +1,417 @@
|
||||
import { FUNCTIONS, KEYWORDS, CONSTANTS, FUNCTION_META } from "./inbuilt_symbols.js";
|
||||
|
||||
const AUTOCOMPLETE_STYLE_ID = "mrmth-script-autocomplete-styles";
|
||||
|
||||
function ensureAutocompleteStyles() {
|
||||
if (document.getElementById(AUTOCOMPLETE_STYLE_ID)) return;
|
||||
|
||||
const style = document.createElement("style");
|
||||
style.id = AUTOCOMPLETE_STYLE_ID;
|
||||
style.textContent = `
|
||||
.mrmth-autocomplete {
|
||||
position: absolute;
|
||||
z-index: 20;
|
||||
min-width: 180px;
|
||||
max-width: min(420px, 100%);
|
||||
max-height: 220px;
|
||||
overflow-y: auto;
|
||||
margin: 0;
|
||||
padding: 4px 0;
|
||||
list-style: none;
|
||||
border: 1px solid rgba(255, 255, 255, 0.18);
|
||||
border-radius: 8px;
|
||||
background: rgba(18, 20, 24, 0.97);
|
||||
box-shadow: 0 8px 24px rgba(0, 0, 0, 0.45);
|
||||
font-family: monospace;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.mrmth-autocomplete-item {
|
||||
display: flex;
|
||||
align-items: baseline;
|
||||
justify-content: space-between;
|
||||
gap: 12px;
|
||||
padding: 5px 10px;
|
||||
cursor: pointer;
|
||||
color: #ecf0f1;
|
||||
}
|
||||
|
||||
.mrmth-autocomplete-item.is-selected {
|
||||
background: rgba(142, 68, 173, 0.35);
|
||||
}
|
||||
|
||||
.mrmth-autocomplete-item .mrmth-ac-kind {
|
||||
flex-shrink: 0;
|
||||
font-size: 10px;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.04em;
|
||||
color: #9aa0a6;
|
||||
}
|
||||
|
||||
.mrmth-autocomplete-item .mrmth-ac-name {
|
||||
color: #c39bd3;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.mrmth-autocomplete-item.is-keyword .mrmth-ac-name {
|
||||
color: #e74c3c;
|
||||
}
|
||||
|
||||
.mrmth-autocomplete-item.is-constant .mrmth-ac-name {
|
||||
color: #f1c40f;
|
||||
}
|
||||
|
||||
.mrmth-autocomplete-item .mrmth-ac-hint {
|
||||
color: #7f8c8d;
|
||||
font-size: 11px;
|
||||
white-space: nowrap;
|
||||
}
|
||||
`;
|
||||
document.head.appendChild(style);
|
||||
}
|
||||
|
||||
function isCursorInStringOrComment(text, cursor) {
|
||||
let inString = false;
|
||||
let stringChar = "";
|
||||
let inLineComment = false;
|
||||
let inBlockComment = false;
|
||||
|
||||
for (let i = 0; i < cursor; i++) {
|
||||
const ch = text[i];
|
||||
const next = text[i + 1];
|
||||
|
||||
if (inLineComment) {
|
||||
if (ch === "\n") inLineComment = false;
|
||||
continue;
|
||||
}
|
||||
if (inBlockComment) {
|
||||
if (ch === "*" && next === "/") {
|
||||
inBlockComment = false;
|
||||
i++;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if (inString) {
|
||||
if (ch === "\\") {
|
||||
i++;
|
||||
continue;
|
||||
}
|
||||
if (ch === stringChar) inString = false;
|
||||
continue;
|
||||
}
|
||||
if (ch === "#") {
|
||||
inLineComment = true;
|
||||
continue;
|
||||
}
|
||||
if (ch === "/" && next === "*") {
|
||||
inBlockComment = true;
|
||||
i++;
|
||||
continue;
|
||||
}
|
||||
if (ch === '"' || ch === "'") {
|
||||
inString = true;
|
||||
stringChar = ch;
|
||||
}
|
||||
}
|
||||
|
||||
return inString || inBlockComment;
|
||||
}
|
||||
|
||||
function getWordPrefix(text, cursor) {
|
||||
const before = text.slice(0, cursor);
|
||||
const match = before.match(/[a-zA-Z_][a-zA-Z0-9_]*$/);
|
||||
if (!match) return null;
|
||||
return { word: match[0], start: cursor - match[0].length };
|
||||
}
|
||||
|
||||
function formatArgHint(meta) {
|
||||
if (!meta) return "";
|
||||
if (meta.maxArgs === null) {
|
||||
if (meta.minArgs <= 1) return "(…)";
|
||||
return `(${meta.minArgs}+ args)`;
|
||||
}
|
||||
if (meta.minArgs === meta.maxArgs) {
|
||||
if (meta.minArgs === 0) return "()";
|
||||
if (meta.minArgs === 1) return "(x)";
|
||||
return `(${meta.minArgs} args)`;
|
||||
}
|
||||
return `(${meta.minArgs}–${meta.maxArgs} args)`;
|
||||
}
|
||||
|
||||
function buildSuggestions(prefix) {
|
||||
const lower = prefix.toLowerCase();
|
||||
const items = [];
|
||||
|
||||
for (const name of FUNCTIONS) {
|
||||
if (!name.toLowerCase().startsWith(lower)) continue;
|
||||
const meta = FUNCTION_META[name];
|
||||
items.push({
|
||||
name,
|
||||
kind: "function",
|
||||
hint: meta?.snippet || `${name}()`,
|
||||
detail: formatArgHint(meta),
|
||||
insertText: meta?.snippet || `${name}()`,
|
||||
});
|
||||
}
|
||||
for (const name of KEYWORDS) {
|
||||
if (!name.toLowerCase().startsWith(lower)) continue;
|
||||
items.push({
|
||||
name,
|
||||
kind: "keyword",
|
||||
hint: name,
|
||||
detail: "",
|
||||
insertText: name,
|
||||
});
|
||||
}
|
||||
for (const name of CONSTANTS) {
|
||||
if (!name.toLowerCase().startsWith(lower)) continue;
|
||||
items.push({
|
||||
name,
|
||||
kind: "constant",
|
||||
hint: name,
|
||||
detail: "",
|
||||
insertText: name,
|
||||
});
|
||||
}
|
||||
|
||||
items.sort((a, b) => {
|
||||
const kindOrder = { function: 0, constant: 1, keyword: 2 };
|
||||
const ka = kindOrder[a.kind] ?? 9;
|
||||
const kb = kindOrder[b.kind] ?? 9;
|
||||
if (ka !== kb) return ka - kb;
|
||||
return a.name.localeCompare(b.name);
|
||||
});
|
||||
|
||||
return items.slice(0, 40);
|
||||
}
|
||||
|
||||
function getCaretCoordinates(textarea, position) {
|
||||
const style = window.getComputedStyle(textarea);
|
||||
const div = document.createElement("div");
|
||||
const props = [
|
||||
"fontFamily", "fontSize", "fontWeight", "fontStyle", "lineHeight",
|
||||
"letterSpacing", "textTransform", "wordSpacing", "textIndent",
|
||||
"whiteSpace", "wordBreak", "overflowWrap", "paddingTop", "paddingRight",
|
||||
"paddingBottom", "paddingLeft", "borderTopWidth", "borderRightWidth",
|
||||
"borderBottomWidth", "borderLeftWidth", "boxSizing",
|
||||
];
|
||||
div.style.position = "absolute";
|
||||
div.style.visibility = "hidden";
|
||||
div.style.whiteSpace = "pre-wrap";
|
||||
div.style.overflowWrap = style.overflowWrap;
|
||||
div.style.wordBreak = style.wordBreak;
|
||||
div.style.width = `${textarea.clientWidth}px`;
|
||||
for (const prop of props) {
|
||||
div.style[prop] = style[prop];
|
||||
}
|
||||
|
||||
const text = textarea.value.substring(0, position);
|
||||
const span = document.createElement("span");
|
||||
span.textContent = text;
|
||||
div.appendChild(span);
|
||||
const marker = document.createElement("span");
|
||||
marker.textContent = textarea.value.substring(position) || ".";
|
||||
div.appendChild(marker);
|
||||
document.body.appendChild(div);
|
||||
|
||||
const top = marker.offsetTop;
|
||||
const left = marker.offsetLeft;
|
||||
div.remove();
|
||||
return { top, left };
|
||||
}
|
||||
|
||||
/**
|
||||
* Attach identifier autocomplete to a script textarea.
|
||||
* @param {HTMLTextAreaElement} textarea
|
||||
* @param {HTMLElement} containerEl - positioned parent (e.g. .mrmth-editor-container)
|
||||
* @returns {{ destroy: () => void, close: () => void }}
|
||||
*/
|
||||
export function attachAutocomplete(textarea, containerEl) {
|
||||
ensureAutocompleteStyles();
|
||||
|
||||
const dropdown = document.createElement("ul");
|
||||
dropdown.className = "mrmth-autocomplete";
|
||||
dropdown.hidden = true;
|
||||
containerEl.appendChild(dropdown);
|
||||
|
||||
let items = [];
|
||||
let selectedIndex = 0;
|
||||
let prefixInfo = null;
|
||||
let open = false;
|
||||
|
||||
const close = () => {
|
||||
open = false;
|
||||
dropdown.hidden = true;
|
||||
dropdown.innerHTML = "";
|
||||
items = [];
|
||||
selectedIndex = 0;
|
||||
prefixInfo = null;
|
||||
};
|
||||
|
||||
const render = () => {
|
||||
dropdown.innerHTML = "";
|
||||
items.forEach((item, index) => {
|
||||
const li = document.createElement("li");
|
||||
li.className = `mrmth-autocomplete-item is-${item.kind}${index === selectedIndex ? " is-selected" : ""}`;
|
||||
li.dataset.index = String(index);
|
||||
|
||||
const left = document.createElement("span");
|
||||
left.className = "mrmth-ac-name";
|
||||
left.textContent = item.name;
|
||||
|
||||
const right = document.createElement("span");
|
||||
right.className = "mrmth-ac-hint";
|
||||
right.textContent = item.detail || item.hint;
|
||||
|
||||
const kind = document.createElement("span");
|
||||
kind.className = "mrmth-ac-kind";
|
||||
kind.textContent = item.kind;
|
||||
|
||||
li.appendChild(left);
|
||||
li.appendChild(right);
|
||||
li.appendChild(kind);
|
||||
li.addEventListener("mousedown", (e) => {
|
||||
e.preventDefault();
|
||||
selectedIndex = index;
|
||||
applySelected();
|
||||
});
|
||||
dropdown.appendChild(li);
|
||||
});
|
||||
};
|
||||
|
||||
const positionDropdown = () => {
|
||||
if (!prefixInfo) return;
|
||||
const coords = getCaretCoordinates(textarea, prefixInfo.start);
|
||||
dropdown.style.left = `${coords.left}px`;
|
||||
dropdown.style.top = `${coords.top + 18}px`;
|
||||
};
|
||||
|
||||
const openWith = (nextItems, nextPrefix) => {
|
||||
if (!nextItems.length) {
|
||||
close();
|
||||
return;
|
||||
}
|
||||
items = nextItems;
|
||||
selectedIndex = 0;
|
||||
prefixInfo = nextPrefix;
|
||||
open = true;
|
||||
dropdown.hidden = false;
|
||||
render();
|
||||
positionDropdown();
|
||||
};
|
||||
|
||||
const applySelected = () => {
|
||||
if (!open || !prefixInfo || !items[selectedIndex]) return;
|
||||
|
||||
const item = items[selectedIndex];
|
||||
const before = textarea.value.slice(0, prefixInfo.start);
|
||||
const after = textarea.value.slice(textarea.selectionEnd);
|
||||
const insert = item.insertText;
|
||||
textarea.value = `${before}${insert}${after}`;
|
||||
|
||||
const cursorPos = before.length + insert.length;
|
||||
if (item.kind === "function" && insert.endsWith("()")) {
|
||||
textarea.selectionStart = textarea.selectionEnd = cursorPos - 1;
|
||||
} else {
|
||||
textarea.selectionStart = textarea.selectionEnd = cursorPos;
|
||||
}
|
||||
|
||||
textarea.dispatchEvent(new Event("input", { bubbles: true }));
|
||||
close();
|
||||
};
|
||||
|
||||
const maybeOpen = (force = false) => {
|
||||
const cursor = textarea.selectionStart;
|
||||
if (cursor !== textarea.selectionEnd) {
|
||||
close();
|
||||
return;
|
||||
}
|
||||
if (isCursorInStringOrComment(textarea.value, cursor)) {
|
||||
close();
|
||||
return;
|
||||
}
|
||||
|
||||
const info = getWordPrefix(textarea.value, cursor);
|
||||
if (!info || (!force && info.word.length < 1)) {
|
||||
close();
|
||||
return;
|
||||
}
|
||||
|
||||
const suggestions = buildSuggestions(info.word);
|
||||
if (!suggestions.length) {
|
||||
close();
|
||||
return;
|
||||
}
|
||||
openWith(suggestions, info);
|
||||
};
|
||||
|
||||
const onInput = () => {
|
||||
if (!open) {
|
||||
const info = getWordPrefix(textarea.value, textarea.selectionStart);
|
||||
if (info && info.word.length >= 2) {
|
||||
maybeOpen(false);
|
||||
}
|
||||
return;
|
||||
}
|
||||
maybeOpen(false);
|
||||
};
|
||||
|
||||
const onKeyDown = (e) => {
|
||||
if (e.ctrlKey && e.key === " ") {
|
||||
e.preventDefault();
|
||||
maybeOpen(true);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!open) return;
|
||||
|
||||
if (e.key === "ArrowDown") {
|
||||
e.preventDefault();
|
||||
selectedIndex = (selectedIndex + 1) % items.length;
|
||||
render();
|
||||
return;
|
||||
}
|
||||
if (e.key === "ArrowUp") {
|
||||
e.preventDefault();
|
||||
selectedIndex = (selectedIndex - 1 + items.length) % items.length;
|
||||
render();
|
||||
return;
|
||||
}
|
||||
if (e.key === "Enter" || e.key === "Tab") {
|
||||
e.preventDefault();
|
||||
applySelected();
|
||||
return;
|
||||
}
|
||||
if (e.key === "Escape") {
|
||||
e.preventDefault();
|
||||
close();
|
||||
}
|
||||
};
|
||||
|
||||
const onBlur = () => {
|
||||
setTimeout(close, 120);
|
||||
};
|
||||
|
||||
const onScroll = () => {
|
||||
if (open) positionDropdown();
|
||||
};
|
||||
|
||||
textarea.addEventListener("input", onInput);
|
||||
textarea.addEventListener("keydown", onKeyDown);
|
||||
textarea.addEventListener("blur", onBlur);
|
||||
textarea.addEventListener("scroll", onScroll);
|
||||
|
||||
return {
|
||||
close,
|
||||
destroy() {
|
||||
close();
|
||||
dropdown.remove();
|
||||
textarea.removeEventListener("input", onInput);
|
||||
textarea.removeEventListener("keydown", onKeyDown);
|
||||
textarea.removeEventListener("blur", onBlur);
|
||||
textarea.removeEventListener("scroll", onScroll);
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
export { buildSuggestions, getWordPrefix, isCursorInStringOrComment, formatArgHint };
|
||||
+238
-1
@@ -10,4 +10,241 @@ export const CONSTANTS = new Set([
|
||||
|
||||
export const FUNCTIONS = new Set([
|
||||
"abs", "acos", "acosh", "all", "angle", "any", "append", "argmax", "argmin", "argsort", "asin", "asinh", "atan", "atan2", "atanh", "band", "batch_shuffle", "bitcount", "bitwise_and", "bitwise_not", "bitwise_or", "bitwise_xor", "blur", "bnot", "bor", "botk", "botk_ind", "botk_indices", "bxor", "cat", "ceil", "cellular", "cellular_noise", "cielab_to_rgb", "clamp", "cnt", "concat", "concatenate", "conv", "convolution", "corr", "correlation", "cos", "cosh", "cosine_similarity", "cossim", "count", "cov", "crop", "cross", "cubic", "cubic_ease", "cumprod", "cumsum", "dilate", "dist", "distance", "domain_warp", "domain_warp_noise", "dot", "edge", "elastic", "elastic_ease", "entropy", "erf", "erfinv", "erode", "exp", "ezconv", "ezconvolution", "fft", "find", "flatten", "flip", "float", "floor", "flow_ang", "flow_angle", "flow_apply", "flow_mag", "flow_magnitude", "flow_to_image", "fract", "gamma", "gaussian", "gelu", "get_value", "hist", "histogram", "hsv_to_rgb", "ifft", "int", "int_to_rgb", "interpolate_area", "interpolate_linear", "interpolate_nearest", "interpolate_nearest_exact", "join", "length", "lerp", "linspace", "ln", "log", "logspace", "lower", "map", "matmul", "mean", "median", "mode", "moment", "morph_close", "morph_open", "motion_mask", "nan_to_num", "noise", "now", "nvl", "oklab_to_rgb", "overlay", "pad", "percentile", "perlin", "perlin_noise", "perm", "permute", "pinv", "plasma", "plasma_noise", "popcnt", "popcount", "pow", "prcnt", "print", "print_shape", "pshp", "quantile", "quartil", "quartile", "rand", "randb", "randbeta", "randc", "rande", "randg", "randgumbel", "randchi2", "randl", "randln", "randn", "random_bernoulli", "random_beta", "random_cauchy", "random_exponential", "random_gamma", "random_gumbel", "random_chi2", "random_laplace", "random_log_normal", "random_normal", "random_poisson", "random_studentt", "random_uniform", "random_weibull", "randp", "randt", "randu", "randw", "range", "relu", "remap", "replace", "reshape", "rgb_to_cielab", "rgb_to_hsv", "rgb_to_int", "rgb_to_oklab", "ridged", "ridged_noise", "rife", "roll", "round", "rshp", "select", "shape", "shuffle", "sigm", "sign", "sin", "sine", "sine_ease", "sinh", "smax", "smin", "smootherstep", "smoothstep", "snorm", "softmax", "softmin", "softplus", "sort", "split", "sqrt", "stack_clear", "stack_get", "stack_has", "stack_pop", "stack_push", "std", "step", "substr", "substring", "sum", "swap", "tan", "tanh", "tensor", "text_image", "timestamp", "tmax", "tmin", "tnorm", "topk", "topk_ind", "topk_indices", "trim", "turbulence", "unique", "upper", "var", "voronoi", "voronoi_noise", "where", "worley"
|
||||
]);
|
||||
]);
|
||||
|
||||
export const FUNCTION_META = {
|
||||
abs: { minArgs: 1, maxArgs: 1, snippet: "abs()" },
|
||||
acos: { minArgs: 1, maxArgs: 1, snippet: "acos()" },
|
||||
acosh: { minArgs: 1, maxArgs: 1, snippet: "acosh()" },
|
||||
all: { minArgs: 1, maxArgs: 1, snippet: "all()" },
|
||||
angle: { minArgs: 1, maxArgs: 1, snippet: "angle()" },
|
||||
any: { minArgs: 1, maxArgs: 1, snippet: "any()" },
|
||||
append: { minArgs: 2, maxArgs: 2, snippet: "append()" },
|
||||
argmax: { minArgs: 1, maxArgs: 1, snippet: "argmax()" },
|
||||
argmin: { minArgs: 1, maxArgs: 1, snippet: "argmin()" },
|
||||
argsort: { minArgs: 1, maxArgs: 2, snippet: "argsort()" },
|
||||
asin: { minArgs: 1, maxArgs: 1, snippet: "asin()" },
|
||||
asinh: { minArgs: 1, maxArgs: 1, snippet: "asinh()" },
|
||||
atan: { minArgs: 1, maxArgs: 1, snippet: "atan()" },
|
||||
atan2: { minArgs: 2, maxArgs: 2, snippet: "atan2()" },
|
||||
atanh: { minArgs: 1, maxArgs: 1, snippet: "atanh()" },
|
||||
band: { minArgs: 2, maxArgs: 2, snippet: "band()" },
|
||||
batch_shuffle: { minArgs: 2, maxArgs: 2, snippet: "batch_shuffle()" },
|
||||
bitcount: { minArgs: 1, maxArgs: 1, snippet: "bitcount()" },
|
||||
bitwise_and: { minArgs: 2, maxArgs: 2, snippet: "bitwise_and()" },
|
||||
bitwise_not: { minArgs: 1, maxArgs: 1, snippet: "bitwise_not()" },
|
||||
bitwise_or: { minArgs: 2, maxArgs: 2, snippet: "bitwise_or()" },
|
||||
bitwise_xor: { minArgs: 2, maxArgs: 2, snippet: "bitwise_xor()" },
|
||||
blur: { minArgs: 2, maxArgs: 3, snippet: "blur()" },
|
||||
bnot: { minArgs: 1, maxArgs: 1, snippet: "bnot()" },
|
||||
bor: { minArgs: 2, maxArgs: 2, snippet: "bor()" },
|
||||
botk: { minArgs: 2, maxArgs: 2, snippet: "botk()" },
|
||||
botk_ind: { minArgs: 2, maxArgs: 2, snippet: "botk_ind()" },
|
||||
botk_indices: { minArgs: 2, maxArgs: 2, snippet: "botk_indices()" },
|
||||
bxor: { minArgs: 2, maxArgs: 2, snippet: "bxor()" },
|
||||
cat: { minArgs: 2, maxArgs: null, snippet: "cat()" },
|
||||
ceil: { minArgs: 1, maxArgs: 1, snippet: "ceil()" },
|
||||
cellular: { minArgs: 2, maxArgs: 5, snippet: "cellular()" },
|
||||
cellular_noise: { minArgs: 2, maxArgs: 5, snippet: "cellular_noise()" },
|
||||
cielab_to_rgb: { minArgs: 1, maxArgs: 3, snippet: "cielab_to_rgb()" },
|
||||
clamp: { minArgs: 3, maxArgs: 3, snippet: "clamp()" },
|
||||
cnt: { minArgs: 1, maxArgs: 1, snippet: "cnt()" },
|
||||
concat: { minArgs: 2, maxArgs: null, snippet: "concat()" },
|
||||
concatenate: { minArgs: 2, maxArgs: null, snippet: "concatenate()" },
|
||||
conv: { minArgs: 2, maxArgs: null, snippet: "conv()" },
|
||||
convolution: { minArgs: 2, maxArgs: null, snippet: "convolution()" },
|
||||
corr: { minArgs: 2, maxArgs: 2, snippet: "corr()" },
|
||||
correlation: { minArgs: 2, maxArgs: 2, snippet: "correlation()" },
|
||||
cos: { minArgs: 1, maxArgs: 1, snippet: "cos()" },
|
||||
cosh: { minArgs: 1, maxArgs: 1, snippet: "cosh()" },
|
||||
cosine_similarity: { minArgs: 2, maxArgs: 2, snippet: "cosine_similarity()" },
|
||||
cossim: { minArgs: 2, maxArgs: 2, snippet: "cossim()" },
|
||||
count: { minArgs: 1, maxArgs: 1, snippet: "count()" },
|
||||
cov: { minArgs: 2, maxArgs: 2, snippet: "cov()" },
|
||||
crop: { minArgs: 3, maxArgs: 3, snippet: "crop()" },
|
||||
cross: { minArgs: 2, maxArgs: 2, snippet: "cross()" },
|
||||
cubic: { minArgs: 3, maxArgs: 3, snippet: "cubic()" },
|
||||
cubic_ease: { minArgs: 3, maxArgs: 3, snippet: "cubic_ease()" },
|
||||
cumprod: { minArgs: 1, maxArgs: 1, snippet: "cumprod()" },
|
||||
cumsum: { minArgs: 1, maxArgs: 1, snippet: "cumsum()" },
|
||||
dilate: { minArgs: 1, maxArgs: 2, snippet: "dilate()" },
|
||||
dist: { minArgs: 4, maxArgs: 4, snippet: "dist()" },
|
||||
distance: { minArgs: 4, maxArgs: 4, snippet: "distance()" },
|
||||
domain_warp: { minArgs: 4, maxArgs: 8, snippet: "domain_warp()" },
|
||||
domain_warp_noise: { minArgs: 4, maxArgs: 8, snippet: "domain_warp_noise()" },
|
||||
dot: { minArgs: 2, maxArgs: 2, snippet: "dot()" },
|
||||
edge: { minArgs: 1, maxArgs: 2, snippet: "edge()" },
|
||||
elastic: { minArgs: 3, maxArgs: 3, snippet: "elastic()" },
|
||||
elastic_ease: { minArgs: 3, maxArgs: 3, snippet: "elastic_ease()" },
|
||||
entropy: { minArgs: 1, maxArgs: 1, snippet: "entropy()" },
|
||||
erf: { minArgs: 1, maxArgs: 1, snippet: "erf()" },
|
||||
erfinv: { minArgs: 1, maxArgs: 1, snippet: "erfinv()" },
|
||||
erode: { minArgs: 1, maxArgs: 2, snippet: "erode()" },
|
||||
exp: { minArgs: 1, maxArgs: 1, snippet: "exp()" },
|
||||
ezconv: { minArgs: 2, maxArgs: null, snippet: "ezconv()" },
|
||||
ezconvolution: { minArgs: 2, maxArgs: null, snippet: "ezconvolution()" },
|
||||
fft: { minArgs: 1, maxArgs: 1, snippet: "fft()" },
|
||||
find: { minArgs: 2, maxArgs: 2, snippet: "find()" },
|
||||
flatten: { minArgs: 1, maxArgs: 1, snippet: "flatten()" },
|
||||
flip: { minArgs: 2, maxArgs: 2, snippet: "flip()" },
|
||||
float: { minArgs: 1, maxArgs: 1, snippet: "float()" },
|
||||
floor: { minArgs: 1, maxArgs: 1, snippet: "floor()" },
|
||||
flow_ang: { minArgs: 1, maxArgs: 1, snippet: "flow_ang()" },
|
||||
flow_angle: { minArgs: 1, maxArgs: 1, snippet: "flow_angle()" },
|
||||
flow_apply: { minArgs: 2, maxArgs: 2, snippet: "flow_apply()" },
|
||||
flow_mag: { minArgs: 1, maxArgs: 1, snippet: "flow_mag()" },
|
||||
flow_magnitude: { minArgs: 1, maxArgs: 1, snippet: "flow_magnitude()" },
|
||||
flow_to_image: { minArgs: 1, maxArgs: 1, snippet: "flow_to_image()" },
|
||||
fract: { minArgs: 1, maxArgs: 1, snippet: "fract()" },
|
||||
gamma: { minArgs: 1, maxArgs: 1, snippet: "gamma()" },
|
||||
gaussian: { minArgs: 2, maxArgs: 3, snippet: "gaussian()" },
|
||||
gelu: { minArgs: 1, maxArgs: 1, snippet: "gelu()" },
|
||||
get_value: { minArgs: 2, maxArgs: 2, snippet: "get_value()" },
|
||||
hist: { minArgs: 4, maxArgs: 4, snippet: "hist()" },
|
||||
histogram: { minArgs: 4, maxArgs: 4, snippet: "histogram()" },
|
||||
hsv_to_rgb: { minArgs: 1, maxArgs: 4, snippet: "hsv_to_rgb()" },
|
||||
ifft: { minArgs: 1, maxArgs: 2, snippet: "ifft()" },
|
||||
int: { minArgs: 1, maxArgs: 1, snippet: "int()" },
|
||||
int_to_rgb: { minArgs: 1, maxArgs: 1, snippet: "int_to_rgb()" },
|
||||
interpolate_area: { minArgs: 2, maxArgs: 2, snippet: "interpolate_area()" },
|
||||
interpolate_linear: { minArgs: 2, maxArgs: 2, snippet: "interpolate_linear()" },
|
||||
interpolate_nearest: { minArgs: 2, maxArgs: 2, snippet: "interpolate_nearest()" },
|
||||
interpolate_nearest_exact: { minArgs: 2, maxArgs: 2, snippet: "interpolate_nearest_exact()" },
|
||||
join: { minArgs: 1, maxArgs: 2, snippet: "join()" },
|
||||
length: { minArgs: 1, maxArgs: 1, snippet: "length()" },
|
||||
lerp: { minArgs: 3, maxArgs: 3, snippet: "lerp()" },
|
||||
linspace: { minArgs: 3, maxArgs: 3, snippet: "linspace()" },
|
||||
ln: { minArgs: 1, maxArgs: 1, snippet: "ln()" },
|
||||
log: { minArgs: 1, maxArgs: 1, snippet: "log()" },
|
||||
logspace: { minArgs: 4, maxArgs: 4, snippet: "logspace()" },
|
||||
lower: { minArgs: 1, maxArgs: 1, snippet: "lower()" },
|
||||
map: { minArgs: 2, maxArgs: null, snippet: "map()" },
|
||||
matmul: { minArgs: 2, maxArgs: 2, snippet: "matmul()" },
|
||||
mean: { minArgs: 1, maxArgs: 1, snippet: "mean()" },
|
||||
median: { minArgs: 1, maxArgs: 1, snippet: "median()" },
|
||||
mode: { minArgs: 1, maxArgs: 1, snippet: "mode()" },
|
||||
moment: { minArgs: 3, maxArgs: 3, snippet: "moment()" },
|
||||
morph_close: { minArgs: 1, maxArgs: 2, snippet: "morph_close()" },
|
||||
morph_open: { minArgs: 1, maxArgs: 2, snippet: "morph_open()" },
|
||||
motion_mask: { minArgs: 1, maxArgs: 1, snippet: "motion_mask()" },
|
||||
nan_to_num: { minArgs: 4, maxArgs: 4, snippet: "nan_to_num()" },
|
||||
noise: { minArgs: 1, maxArgs: 2, snippet: "noise()" },
|
||||
now: { minArgs: 0, maxArgs: 0, snippet: "now()" },
|
||||
nvl: { minArgs: 4, maxArgs: 4, snippet: "nvl()" },
|
||||
oklab_to_rgb: { minArgs: 1, maxArgs: 3, snippet: "oklab_to_rgb()" },
|
||||
overlay: { minArgs: 3, maxArgs: 4, snippet: "overlay()" },
|
||||
pad: { minArgs: 2, maxArgs: 2, snippet: "pad()" },
|
||||
percentile: { minArgs: 2, maxArgs: 2, snippet: "percentile()" },
|
||||
perlin: { minArgs: 2, maxArgs: 5, snippet: "perlin()" },
|
||||
perlin_noise: { minArgs: 2, maxArgs: 5, snippet: "perlin_noise()" },
|
||||
perm: { minArgs: 2, maxArgs: 2, snippet: "perm()" },
|
||||
permute: { minArgs: 2, maxArgs: 2, snippet: "permute()" },
|
||||
pinv: { minArgs: 1, maxArgs: 1, snippet: "pinv()" },
|
||||
plasma: { minArgs: 2, maxArgs: 5, snippet: "plasma()" },
|
||||
plasma_noise: { minArgs: 2, maxArgs: 5, snippet: "plasma_noise()" },
|
||||
popcnt: { minArgs: 1, maxArgs: 1, snippet: "popcnt()" },
|
||||
popcount: { minArgs: 1, maxArgs: 1, snippet: "popcount()" },
|
||||
pow: { minArgs: 2, maxArgs: 2, snippet: "pow()" },
|
||||
prcnt: { minArgs: 2, maxArgs: 2, snippet: "prcnt()" },
|
||||
print: { minArgs: 1, maxArgs: 1, snippet: "print()" },
|
||||
print_shape: { minArgs: 1, maxArgs: 1, snippet: "print_shape()" },
|
||||
pshp: { minArgs: 1, maxArgs: 1, snippet: "pshp()" },
|
||||
quantile: { minArgs: 2, maxArgs: 2, snippet: "quantile()" },
|
||||
quartil: { minArgs: 2, maxArgs: 2, snippet: "quartil()" },
|
||||
quartile: { minArgs: 2, maxArgs: 2, snippet: "quartile()" },
|
||||
rand: { minArgs: 1, maxArgs: 2, snippet: "rand()" },
|
||||
randb: { minArgs: 2, maxArgs: 3, snippet: "randb()" },
|
||||
randbeta: { minArgs: 3, maxArgs: 4, snippet: "randbeta()" },
|
||||
randc: { minArgs: 3, maxArgs: 4, snippet: "randc()" },
|
||||
rande: { minArgs: 2, maxArgs: 3, snippet: "rande()" },
|
||||
randg: { minArgs: 3, maxArgs: 4, snippet: "randg()" },
|
||||
randgumbel: { minArgs: 3, maxArgs: 4, snippet: "randgumbel()" },
|
||||
randchi2: { minArgs: 2, maxArgs: 3, snippet: "randchi2()" },
|
||||
randl: { minArgs: 3, maxArgs: 4, snippet: "randl()" },
|
||||
randln: { minArgs: 3, maxArgs: 4, snippet: "randln()" },
|
||||
randn: { minArgs: 1, maxArgs: 2, snippet: "randn()" },
|
||||
random_bernoulli: { minArgs: 2, maxArgs: 3, snippet: "random_bernoulli()" },
|
||||
random_beta: { minArgs: 3, maxArgs: 4, snippet: "random_beta()" },
|
||||
random_cauchy: { minArgs: 3, maxArgs: 4, snippet: "random_cauchy()" },
|
||||
random_exponential: { minArgs: 2, maxArgs: 3, snippet: "random_exponential()" },
|
||||
random_gamma: { minArgs: 3, maxArgs: 4, snippet: "random_gamma()" },
|
||||
random_gumbel: { minArgs: 3, maxArgs: 4, snippet: "random_gumbel()" },
|
||||
random_chi2: { minArgs: 2, maxArgs: 3, snippet: "random_chi2()" },
|
||||
random_laplace: { minArgs: 3, maxArgs: 4, snippet: "random_laplace()" },
|
||||
random_log_normal: { minArgs: 3, maxArgs: 4, snippet: "random_log_normal()" },
|
||||
random_normal: { minArgs: 1, maxArgs: 2, snippet: "random_normal()" },
|
||||
random_poisson: { minArgs: 2, maxArgs: 3, snippet: "random_poisson()" },
|
||||
random_studentt: { minArgs: 2, maxArgs: 3, snippet: "random_studentt()" },
|
||||
random_uniform: { minArgs: 1, maxArgs: 2, snippet: "random_uniform()" },
|
||||
random_weibull: { minArgs: 3, maxArgs: 4, snippet: "random_weibull()" },
|
||||
randp: { minArgs: 2, maxArgs: 3, snippet: "randp()" },
|
||||
randt: { minArgs: 2, maxArgs: 3, snippet: "randt()" },
|
||||
randu: { minArgs: 1, maxArgs: 2, snippet: "randu()" },
|
||||
randw: { minArgs: 3, maxArgs: 4, snippet: "randw()" },
|
||||
range: { minArgs: 3, maxArgs: 3, snippet: "range()" },
|
||||
relu: { minArgs: 1, maxArgs: null, snippet: "relu()" },
|
||||
remap: { minArgs: 5, maxArgs: 5, snippet: "remap()" },
|
||||
replace: { minArgs: 3, maxArgs: 3, snippet: "replace()" },
|
||||
reshape: { minArgs: 2, maxArgs: 2, snippet: "reshape()" },
|
||||
rgb_to_cielab: { minArgs: 1, maxArgs: 3, snippet: "rgb_to_cielab()" },
|
||||
rgb_to_hsv: { minArgs: 1, maxArgs: 4, snippet: "rgb_to_hsv()" },
|
||||
rgb_to_int: { minArgs: 1, maxArgs: 3, snippet: "rgb_to_int()" },
|
||||
rgb_to_oklab: { minArgs: 1, maxArgs: 3, snippet: "rgb_to_oklab()" },
|
||||
ridged: { minArgs: 2, maxArgs: 5, snippet: "ridged()" },
|
||||
ridged_noise: { minArgs: 2, maxArgs: 5, snippet: "ridged_noise()" },
|
||||
rife: { minArgs: 4, maxArgs: 5, snippet: "rife()" },
|
||||
roll: { minArgs: 2, maxArgs: 3, snippet: "roll()" },
|
||||
round: { minArgs: 1, maxArgs: 1, snippet: "round()" },
|
||||
rshp: { minArgs: 2, maxArgs: 2, snippet: "rshp()" },
|
||||
select: { minArgs: 2, maxArgs: 2, snippet: "select()" },
|
||||
shape: { minArgs: 1, maxArgs: 1, snippet: "shape()" },
|
||||
shuffle: { minArgs: 2, maxArgs: 2, snippet: "shuffle()" },
|
||||
sigm: { minArgs: 1, maxArgs: 1, snippet: "sigm()" },
|
||||
sign: { minArgs: 1, maxArgs: 1, snippet: "sign()" },
|
||||
sin: { minArgs: 1, maxArgs: 1, snippet: "sin()" },
|
||||
sine: { minArgs: 3, maxArgs: 3, snippet: "sine()" },
|
||||
sine_ease: { minArgs: 3, maxArgs: 3, snippet: "sine_ease()" },
|
||||
sinh: { minArgs: 1, maxArgs: 1, snippet: "sinh()" },
|
||||
smax: { minArgs: 1, maxArgs: null, snippet: "smax()" },
|
||||
smin: { minArgs: 1, maxArgs: null, snippet: "smin()" },
|
||||
smootherstep: { minArgs: 3, maxArgs: 3, snippet: "smootherstep()" },
|
||||
smoothstep: { minArgs: 3, maxArgs: 3, snippet: "smoothstep()" },
|
||||
snorm: { minArgs: 1, maxArgs: 1, snippet: "snorm()" },
|
||||
softmax: { minArgs: 1, maxArgs: 2, snippet: "softmax()" },
|
||||
softmin: { minArgs: 1, maxArgs: 2, snippet: "softmin()" },
|
||||
softplus: { minArgs: 1, maxArgs: 1, snippet: "softplus()" },
|
||||
sort: { minArgs: 1, maxArgs: 1, snippet: "sort()" },
|
||||
split: { minArgs: 1, maxArgs: 2, snippet: "split()" },
|
||||
sqrt: { minArgs: 1, maxArgs: 1, snippet: "sqrt()" },
|
||||
stack_clear: { minArgs: 1, maxArgs: 1, snippet: "stack_clear()" },
|
||||
stack_get: { minArgs: 1, maxArgs: 1, snippet: "stack_get()" },
|
||||
stack_has: { minArgs: 1, maxArgs: 1, snippet: "stack_has()" },
|
||||
stack_pop: { minArgs: 1, maxArgs: 1, snippet: "stack_pop()" },
|
||||
stack_push: { minArgs: 2, maxArgs: 2, snippet: "stack_push()" },
|
||||
std: { minArgs: 1, maxArgs: 1, snippet: "std()" },
|
||||
step: { minArgs: 2, maxArgs: 2, snippet: "step()" },
|
||||
substr: { minArgs: 2, maxArgs: 3, snippet: "substr()" },
|
||||
substring: { minArgs: 2, maxArgs: 3, snippet: "substring()" },
|
||||
sum: { minArgs: 1, maxArgs: 1, snippet: "sum()" },
|
||||
swap: { minArgs: 4, maxArgs: 4, snippet: "swap()" },
|
||||
tan: { minArgs: 1, maxArgs: 1, snippet: "tan()" },
|
||||
tanh: { minArgs: 1, maxArgs: 1, snippet: "tanh()" },
|
||||
tensor: { minArgs: 2, maxArgs: 3, snippet: "tensor()" },
|
||||
text_image: { minArgs: 3, maxArgs: 9, snippet: "text_image()" },
|
||||
timestamp: { minArgs: 0, maxArgs: 0, snippet: "timestamp()" },
|
||||
tmax: { minArgs: 2, maxArgs: 2, snippet: "tmax()" },
|
||||
tmin: { minArgs: 2, maxArgs: 2, snippet: "tmin()" },
|
||||
tnorm: { minArgs: 1, maxArgs: 1, snippet: "tnorm()" },
|
||||
topk: { minArgs: 2, maxArgs: 2, snippet: "topk()" },
|
||||
topk_ind: { minArgs: 2, maxArgs: 2, snippet: "topk_ind()" },
|
||||
topk_indices: { minArgs: 2, maxArgs: 2, snippet: "topk_indices()" },
|
||||
trim: { minArgs: 1, maxArgs: 1, snippet: "trim()" },
|
||||
turbulence: { minArgs: 2, maxArgs: 5, snippet: "turbulence()" },
|
||||
unique: { minArgs: 1, maxArgs: 1, snippet: "unique()" },
|
||||
upper: { minArgs: 1, maxArgs: 1, snippet: "upper()" },
|
||||
var: { minArgs: 1, maxArgs: 1, snippet: "var()" },
|
||||
voronoi: { minArgs: 2, maxArgs: 5, snippet: "voronoi()" },
|
||||
voronoi_noise: { minArgs: 2, maxArgs: 5, snippet: "voronoi_noise()" },
|
||||
where: { minArgs: 3, maxArgs: 3, snippet: "where()" },
|
||||
worley: { minArgs: 2, maxArgs: 5, snippet: "worley()" },
|
||||
};
|
||||
@@ -1,5 +1,6 @@
|
||||
import { app } from "/scripts/app.js";
|
||||
import { KEYWORDS, CONSTANTS, FUNCTIONS } from "./inbuilt_symbols.js";
|
||||
import { attachAutocomplete } from "./autocomplete.js";
|
||||
|
||||
const STYLE_ID = "mrmth-script-line-numbers-unified";
|
||||
|
||||
@@ -167,6 +168,7 @@ if (!window.__mrmthScriptInputUnifiedInit) {
|
||||
function isLikelyScriptTextarea(el) {
|
||||
if (!(el instanceof HTMLTextAreaElement)) return false;
|
||||
if (el.dataset.mrmthEnhanced === "1") return false;
|
||||
if (el.closest('[data-mrmth-script-widget="vue"]')) return false;
|
||||
|
||||
const attrs = [
|
||||
el.name,
|
||||
@@ -473,6 +475,7 @@ if (!window.__mrmthScriptInputUnifiedInit) {
|
||||
textarea.autocorrect = "off";
|
||||
|
||||
addBracketAutoClose(textarea);
|
||||
attachAutocomplete(textarea, editorContainer);
|
||||
const cs = getComputedStyle(textarea);
|
||||
syntaxLayer.style.fontFamily = cs.fontFamily;
|
||||
syntaxLayer.style.fontSize = cs.fontSize;
|
||||
|
||||
Reference in New Issue
Block a user