From 833b9c449fb3cd3f10457227ef7b2146789373c0 Mon Sep 17 00:00:00 2001 From: sadguitarius Date: Mon, 13 Oct 2025 11:45:03 -0700 Subject: [PATCH 1/4] add snippets for derived classes --- scide_scnvim/Classes/SCNvim.sc | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/scide_scnvim/Classes/SCNvim.sc b/scide_scnvim/Classes/SCNvim.sc index d0b8ad37..f91f0a4b 100644 --- a/scide_scnvim/Classes/SCNvim.sc +++ b/scide_scnvim/Classes/SCNvim.sc @@ -145,9 +145,15 @@ SCNvim { Class.allClasses.do {arg klass; var className, argList, signature; + var currClass = klass; if (klass.asString.beginsWith("Meta_").not) { + // get methods from superclass for derived classes + // TODO: does this catch all the classes we need? + while ({currClass.class.methods.isNil}, { + currClass = currClass.superclass; + }); // collect all creation methods - klass.class.methods.do {arg meth; + currClass.class.methods.do {arg meth; var index, snippet; var snippetName; // classvars with getter/setters produces an error From 9bb1473b789b21b990d39a6ac9ff88d83cb745bf Mon Sep 17 00:00:00 2001 From: sadguitarius Date: Fri, 22 May 2026 12:43:40 -0700 Subject: [PATCH 2/4] fix toJSON error and other miscellaneous syntax errors --- lua/scnvim/commands.lua | 2 +- lua/scnvim/config.lua | 2 +- lua/scnvim/editor.lua | 6 +- lua/scnvim/map.lua | 2 +- lua/scnvim/sclang.lua | 1 + lua/scnvim/signature.lua | 2 +- scide_scnvim/Classes/SCNvim.sc | 546 ++++++++++---------- scide_scnvim/Classes/SCNvimDoc/SCNvimDoc.sc | 197 ++++--- 8 files changed, 378 insertions(+), 380 deletions(-) diff --git a/lua/scnvim/commands.lua b/lua/scnvim/commands.lua index 686ea36e..8ccf270c 100644 --- a/lua/scnvim/commands.lua +++ b/lua/scnvim/commands.lua @@ -24,7 +24,7 @@ return function() print('[scnvim] Assets written to ' .. get_cache_dir()) end sclang.generate_assets(on_done) - end, 'Generate syntax highlightning and snippets') + end, 'Generate syntax highlighting and snippets') local options = { nargs = 1, desc = 'Open help for subject' } local open_help = function(tbl) diff --git a/lua/scnvim/config.lua b/lua/scnvim/config.lua index ecc9c03b..ff6ab114 100644 --- a/lua/scnvim/config.lua +++ b/lua/scnvim/config.lua @@ -100,7 +100,7 @@ local default = { border = 'single', }, callback = function(id) - vim.api.nvim_win_set_option(id, 'winblend', 10) + vim.api.nvim_set_option_value('winblend', 10, {win = id}) end, }, }, diff --git a/lua/scnvim/editor.lua b/lua/scnvim/editor.lua index 845946ef..22e828c2 100644 --- a/lua/scnvim/editor.lua +++ b/lua/scnvim/editor.lua @@ -69,6 +69,7 @@ local function flash_region(start, finish) if repeats > 1 then local count = 0 local timer = uv.new_timer() + assert(timer, 'Could not create timer') timer:start( duration, duration, @@ -115,11 +116,12 @@ local function fade_region(start, finish) anchor = lstart > 0 and 'NW' or 'SE', } local id = api.nvim_open_win(buf, false, options) - api.nvim_win_set_option(id, 'winhl', 'Normal:' .. 'SCNvimEval') + api.nvim_set_option_value('winhl', 'Normal:' .. 'SCNvimEval', {win = id}) local timer = uv.new_timer() local rate = 50 local accum = 0 local duration = math.floor(config.editor.highlight.fade.duration) + assert(timer, 'Could not create timer') timer:start( 0, rate, @@ -129,7 +131,7 @@ local function fade_region(start, finish) accum = duration end local value = math.pow(accum / duration, 2.5) - api.nvim_win_set_option(id, 'winblend', math.floor(100 * value)) + api.nvim_set_option_value('winblend', math.floor(100 * value), {win = id}) if accum >= duration then timer:stop() api.nvim_win_close(id, true) diff --git a/lua/scnvim/map.lua b/lua/scnvim/map.lua index 5078f38b..9aa975c5 100644 --- a/lua/scnvim/map.lua +++ b/lua/scnvim/map.lua @@ -66,7 +66,7 @@ local map_expr = function(expr, modes, options) modes = type(modes) == 'string' and { modes } or modes options = options or {} options.silent = options.silent == nil and true or options.silent - options.desc = options.desc or 'sclang: ' .. expr + options.desc = options.desc or ('sclang: ' .. expr) return map(function() require('scnvim.sclang').send(expr, options.silent) end, modes, options) diff --git a/lua/scnvim/sclang.lua b/lua/scnvim/sclang.lua index 0e3f1dfc..51a1d50b 100644 --- a/lua/scnvim/sclang.lua +++ b/lua/scnvim/sclang.lua @@ -231,6 +231,7 @@ function M.stop(_, callback) udp.stop_server() M.send('0.exit', true) local timer = uv.new_timer() + assert(timer, 'Could not create timer') timer:start(1000, 0, function() if M.proc then local ret = M.proc:kill 'sigkill' diff --git a/lua/scnvim/signature.lua b/lua/scnvim/signature.lua index 59c9ff10..2a1fba31 100644 --- a/lua/scnvim/signature.lua +++ b/lua/scnvim/signature.lua @@ -29,7 +29,7 @@ local function extract_objects_helper(str) objects = vim.tbl_map(function(s) return vim.split(s, ',', true) end, objects) - objects = vim.tbl_flatten(objects) + objects = vim.iter(objects):flatten():totable() objects = vim.tbl_map(function(s) -- filter out empty strings (nvim 0.5.1 compatability fix, use -- vim.split(..., {trimempty = true}) for nvim 0.6) diff --git a/scide_scnvim/Classes/SCNvim.sc b/scide_scnvim/Classes/SCNvim.sc index fc060385..fa8bcca4 100644 --- a/scide_scnvim/Classes/SCNvim.sc +++ b/scide_scnvim/Classes/SCNvim.sc @@ -1,275 +1,275 @@ SCNvim { - classvar <>netAddr; - classvar <>currentPath; - classvar <>port; - - *sendJSON {|data| - var json; - if (netAddr.isNil) { - netAddr = NetAddr("127.0.0.1", SCNvim.port); - }; - json = SCNvimJSON.stringify(data); - if (json.notNil) { - netAddr.sendRaw(json); - } { - "[scnvim] could not encode to json: %".format(data).warn; - } - } - - *luaeval{|luacode| - SCNvim.sendJSON((action: "luaeval", args: luacode)) - } - - *eval {|expr, callback_id| - var result = expr.interpret; - result = (action: "eval", args: (result: result, id: callback_id)); - SCNvim.sendJSON(result); - } - - *updateStatusLine {arg interval=1; - var stlFunc = { - var serverStatus, data; - var peakCPU, avgCPU, numUGens, numSynths; - var server = Server.default; - var cmd; - if (server.serverRunning) { - peakCPU = server.peakCPU.trunc(0.01); - avgCPU = server.avgCPU.trunc(0.01); - numUGens = "%u".format(server.numUGens); - numSynths = "%s".format(server.numSynths); - serverStatus = "%\\% %\\% % %".format( - peakCPU, avgCPU, numUGens, numSynths - ); - cmd = "require'scnvim.statusline'.set_server_status('%')".format(serverStatus); - SCNvim.luaeval(cmd); - } - }; - SkipJack(stlFunc, interval, name: "scnvim_statusline"); - } - - *generateAssets {|cacheDir, snippetFormat = "ultisnips"| - var tagsPath = cacheDir +/+ "tags"; - var syntaxPath = cacheDir +/+ "classes.vim"; - var snippetPath = cacheDir; - case - {snippetFormat == "ultisnips"} - { - snippetPath = snippetPath +/+ "supercollider.snippets"; - } - {snippetFormat == "snippets.nvim" or: { snippetFormat == "luasnip" }} - { - snippetPath = snippetPath +/+ "scnvim_snippets.lua"; - } - { - "Unrecognized snippet format: '%'".format(snippetFormat).warn; - snippetPath = nil; - }; - Routine.run { - SCNvim.generateTags(tagsPath); - SCNvim.generateSyntax(syntaxPath); - if (snippetPath.notNil) { - SCNvim.generateSnippets(snippetPath, snippetFormat); - } - }; - } - - *generateSyntax {arg outputPath; - var path, file, classes; - classes = Class.allClasses.collect {|class| - class.asString ++ " "; - }; - path = outputPath.standardizePath; - file = File.open(path, "w"); - file.write("syn keyword scObject "); - file.putAll(classes); - file.close; - "Generated syntax file: %".format(path).postln; - } - - // copied from SCVim.sc - // modified to produce a sorted tags file - // GPLv3 license - *generateTags {arg outputPath; - var tagPath, tagFile; - var tags = []; - - tagPath = outputPath ? "~/.sctags"; - tagPath = tagPath.standardizePath; - - tagFile = File.open(tagPath, "w"); - - tagFile.write('!_TAG_FILE_FORMAT 2 /extended format; --format=1 will not append ;" to lines/'.asString ++ Char.nl); - tagFile.write("!_TAG_FILE_SORTED 1 /0=unsorted, 1=sorted, 2=foldcase/" ++ Char.nl); - tagFile.write("!_TAG_PROGRAM_AUTHOR Stephen Lumenta /stephen.lumenta@gmail.com/" ++ Char.nl); - tagFile.write("!_TAG_PROGRAM_NAME SCNVim.sc//" ++ Char.nl); - tagFile.write("!_TAG_PROGRAM_URL https://github.com/davidgranstrom/scnvim" ++ Char.nl); - tagFile.write("!_TAG_PROGRAM_VERSION 2.0//" ++ Char.nl); - - Class.allClasses.do {arg klass; - var klassName, klassFilename, klassSearchString; - var result; - - klassName = klass.asString; - klassFilename = klass.filenameSymbol; - // use a symbol and convert to string to avoid the "open ended - // string" error on class lib compiliation - klassSearchString = '/^%/;"%%'.asString.format(klassName, Char.tab, "c"); - - result = klassName ++ Char.tab ++ klassFilename ++ Char.tab ++ klassSearchString ++ Char.nl; - tags = tags.add(result); - - klass.methods.do {arg meth; - var methName, methFilename, methSearchString; - methName = meth.name; - methFilename = meth.filenameSymbol; - methSearchString = '/% {/;"%%'.asString.format(methName, Char.tab, "m"); - result = methName ++ Char.tab ++ methFilename ++ Char.tab ++ methSearchString ++ Char.nl; - tags = tags.add(result); - } - }; - - tags = tags.sort; - tagFile.putAll(tags); - tagFile.close; - "Generated tags file: %".format(tagPath).postln; - } - - *generateSnippets {arg outputPath, snippetFormat; - var file, path; - var snippets = []; - - path = outputPath ? "~/.scsnippets"; - path = path.standardizePath; - file = File.open(path, "w"); - snippetFormat = snippetFormat ? "ultisnips"; - - Class.allClasses.do {arg klass; - var className, argList, signature; - var currClass = klass; - if (klass.asString.beginsWith("Meta_").not) { - // get methods from superclass for derived classes - // TODO: does this catch all the classes we need? - while ({currClass.class.methods.isNil}, { - currClass = currClass.superclass; - }); - // collect all creation methods - currClass.class.methods.do {arg meth; - var index, snippet; - var snippetName; - var description; - // classvars with getter/setters produces an error - // since we're only interested in creation methods we skip them - try { - snippetName = "%.%".format(klass, meth.name); - signature = Help.methodArgs(snippetName); - }; - - if (signature.notNil and:{signature.isEmpty.not}) { - index = signature.find("("); - className = signature[..index - 1]; - className = className.replace("*", ".").replace(" ", ""); - - if(snippetFormat == "luasnip", { - - // LuaSnip - argList = signature[index..]; - argList = argList.replace("(", "").replace(")", ""); - argList = argList.split($,); - argList = argList.collect {|a, i| - var scArg = a.replace(" ", "").split($:); - var scArgName = scArg[0]; - var scArgVal = scArg[1]; - var snipArgument; - var escapeChars; - - // Create argument name as text node - snipArgument = "t(\"%:\"),".format(scArgName); - - // Escape all characters that might break the snippet - escapeChars = [ - $\\, - $", - $', - ]; - - escapeChars.do {|char| - scArgVal = scArgVal.asString.replace(char, "\\" ++ char.asString); - }; - - // Create argument default value as insert node - snipArgument = snipArgument ++ "i(%, %)".format(i+1, scArgVal.quote); - - // Only add text node with comma if not last item - if(i+1 != argList.size, { - snipArgument = snipArgument ++ ",t(\", \")" - }); - - snipArgument - }; - - argList = "t(\"(\")," ++ argList.join(", ") ++ ", t(\")\"),"; - snippet = "t(\"%\"),".format(className) ++ argList; - - // Not sure why this is necessary but some snippets generate new lines? - snippet = snippet.replace(Char.nl, ""); - - }, { - // UltiSnips, Snippets.nvim - argList = signature[index..]; - argList = argList.replace("(", "").replace(")", ""); - argList = argList.split($,); - argList = argList.collect {|a, i| - "${%:%}".format(i+1, a) - }; - argList = "(" ++ argList.join(", ") ++ ")"; - snippet = className ++ argList; - - }); - - case - {snippetFormat == "ultisnips"} { - snippet = "snippet %\n%\nendsnippet\n".format(snippetName, snippet); - } - {snippetFormat == "snippets.nvim"} { - snippet = "['%'] = [[%]];\n".format(snippetName, snippet); - } - {snippetFormat == "luasnip"} { - description = "Snippet for %, auto generated by SCNvim".format(snippetName); - snippet = "s( {trig = \"%\", name = \"%\", dscr = \"%\" }, {%}),".format(snippetName, snippetName, description, snippet); - }; - snippets = snippets.add(snippet ++ Char.nl); - }; - }; - }; - }; - - case - {snippetFormat == "ultisnips"} { - file.write("# SuperCollider snippets" ++ Char.nl); - file.write("# Snippet generator: SCNvim.sc" ++ Char.nl); - file.putAll(snippets); - } - {snippetFormat == "luasnip"} { - file.write("-- SuperCollider snippets for LuaSnip" ++ Char.nl); - file.write("-- Snippet generator: SCNvim.sc" ++ Char.nl); - file.write("local ls = require'luasnip'" ++ Char.nl); - file.write("local s = ls.snippet " ++ Char.nl); - file.write("local i = ls.insert_node" ++ Char.nl); - file.write("local t = ls.text_node" ++ Char.nl); - file.write("local snippets = {" ++ Char.nl); - file.putAll(snippets); - file.write("}" ++ Char.nl); - file.write("return snippets"); - } - {snippetFormat == "snippets.nvim" } { - file.write("-- SuperCollider snippets for Snippets.nvim" ++ Char.nl); - file.write("-- Snippet generator: SCNvim.sc" ++ Char.nl); - file.write("local snippets = {" ++ Char.nl); - file.putAll(snippets); - file.write("}" ++ Char.nl); - file.write("return snippets"); - }; - file.close; - "Generated snippets file: %".format(path).postln; - } + classvar <>netAddr; + classvar <>currentPath; + classvar <>port; + + *sendJSON {|data| + var json; + if (netAddr.isNil) { + netAddr = NetAddr("127.0.0.1", SCNvim.port); + }; + json = SCNvimJSON.stringify(data); + if (json.notNil) { + netAddr.sendRaw(json); + } { + "[scnvim] could not encode to json: %".format(data).warn; + } + } + + *luaeval{|luacode| + SCNvim.sendJSON((action: "luaeval", args: luacode)) + } + + *eval {|expr, callback_id| + var result = expr.interpret; + result = (action: "eval", args: (result: result, id: callback_id)); + SCNvim.sendJSON(result); + } + + *updateStatusLine {arg interval=1; + var stlFunc = { + var serverStatus, data; + var peakCPU, avgCPU, numUGens, numSynths; + var server = Server.default; + var cmd; + if (server.serverRunning) { + peakCPU = server.peakCPU.trunc(0.01); + avgCPU = server.avgCPU.trunc(0.01); + numUGens = "%u".format(server.numUGens); + numSynths = "%s".format(server.numSynths); + serverStatus = "%\\% %\\% % %".format( + peakCPU, avgCPU, numUGens, numSynths + ); + cmd = "require'scnvim.statusline'.set_server_status('%')".format(serverStatus); + SCNvim.luaeval(cmd); + } + }; + SkipJack(stlFunc, interval, name: "scnvim_statusline"); + } + + *generateAssets {|cacheDir, snippetFormat = "ultisnips"| + var tagsPath = cacheDir +/+ "tags"; + var syntaxPath = cacheDir +/+ "classes.vim"; + var snippetPath = cacheDir; + case + {snippetFormat == "ultisnips"} + { + snippetPath = snippetPath +/+ "supercollider.snippets"; + } + {snippetFormat == "snippets.nvim" or: { snippetFormat == "luasnip" }} + { + snippetPath = snippetPath +/+ "scnvim_snippets.lua"; + } + { + "Unrecognized snippet format: '%'".format(snippetFormat).warn; + snippetPath = nil; + }; + Routine.run { + SCNvim.generateTags(tagsPath); + SCNvim.generateSyntax(syntaxPath); + if (snippetPath.notNil) { + SCNvim.generateSnippets(snippetPath, snippetFormat); + } + }; + } + + *generateSyntax {arg outputPath; + var path, file, classes; + classes = Class.allClasses.collect {|class| + class.asString ++ " "; + }; + path = outputPath.standardizePath; + file = File.open(path, "w"); + file.write("syn keyword scObject "); + file.putAll(classes); + file.close; + "Generated syntax file: %".format(path).postln; + } + + // copied from SCVim.sc + // modified to produce a sorted tags file + // GPLv3 license + *generateTags {arg outputPath; + var tagPath, tagFile; + var tags = []; + + tagPath = outputPath ? "~/.sctags"; + tagPath = tagPath.standardizePath; + + tagFile = File.open(tagPath, "w"); + + tagFile.write('!_TAG_FILE_FORMAT 2 /extended format; --format=1 will not append ;" to lines/'.asString ++ Char.nl); + tagFile.write("!_TAG_FILE_SORTED 1 /0=unsorted, 1=sorted, 2=foldcase/" ++ Char.nl); + tagFile.write("!_TAG_PROGRAM_AUTHOR Stephen Lumenta /stephen.lumenta@gmail.com/" ++ Char.nl); + tagFile.write("!_TAG_PROGRAM_NAME SCNVim.sc//" ++ Char.nl); + tagFile.write("!_TAG_PROGRAM_URL https://github.com/davidgranstrom/scnvim" ++ Char.nl); + tagFile.write("!_TAG_PROGRAM_VERSION 2.0//" ++ Char.nl); + + Class.allClasses.do {arg klass; + var klassName, klassFilename, klassSearchString; + var result; + + klassName = klass.asString; + klassFilename = klass.filenameSymbol; + // use a symbol and convert to string to avoid the "open ended + // string" error on class lib compiliation + klassSearchString = '/^%/;"%%'.asString.format(klassName, Char.tab, "c"); + + result = klassName ++ Char.tab ++ klassFilename ++ Char.tab ++ klassSearchString ++ Char.nl; + tags = tags.add(result); + + klass.methods.do {arg meth; + var methName, methFilename, methSearchString; + methName = meth.name; + methFilename = meth.filenameSymbol; + methSearchString = '/% {/;"%%'.asString.format(methName, Char.tab, "m"); + result = methName ++ Char.tab ++ methFilename ++ Char.tab ++ methSearchString ++ Char.nl; + tags = tags.add(result); + } + }; + + tags = tags.sort; + tagFile.putAll(tags); + tagFile.close; + "Generated tags file: %".format(tagPath).postln; + } + + *generateSnippets {arg outputPath, snippetFormat; + var file, path; + var snippets = []; + + path = outputPath ? "~/.scsnippets"; + path = path.standardizePath; + file = File.open(path, "w"); + snippetFormat = snippetFormat ? "ultisnips"; + + Class.allClasses.do {arg klass; + var className, argList, signature; + if (klass.asString.beginsWith("Meta_").not) { + var currClass = klass; + // get methods from superclass for derived classes + // TODO: should traverse entire heirarchy but this produces too many snippets! + while ({currClass.class.methods.isNil}, { + currClass = currClass.superclass; + }); + // collect all creation methods + currClass.class.methods.do {arg meth; + var index, snippet; + var snippetName; + var description; + // classvars with getter/setters produces an error + // since we're only interested in creation methods we skip them + try { + snippetName = "%.%".format(klass, meth.name); + signature = Help.methodArgs(snippetName); + }; + + if (signature.notNil and:{signature.isEmpty.not}) { + index = signature.find("("); + className = signature[..index - 1]; + className = className.replace("*", ".").replace(" ", ""); + + if(snippetFormat == "luasnip", { + + // LuaSnip + argList = signature[index..]; + argList = argList.replace("(", "").replace(")", ""); + argList = argList.split($,); + argList = argList.collect {|a, i| + var scArg = a.replace(" ", "").split($:); + var scArgName = scArg[0]; + var scArgVal = scArg[1]; + var snipArgument; + var escapeChars; + + // Create argument name as text node + snipArgument = "t(\"%:\"),".format(scArgName); + + // Escape all characters that might break the snippet + escapeChars = [ + $\\, + $", + $', + ]; + + escapeChars.do {|char| + scArgVal = scArgVal.asString.replace(char, "\\" ++ char.asString); + }; + + // Create argument default value as insert node + snipArgument = snipArgument ++ "i(%, %)".format(i+1, scArgVal.quote); + + // Only add text node with comma if not last item + if(i+1 != argList.size, { + snipArgument = snipArgument ++ ",t(\", \")" + }); + + snipArgument + }; + + argList = "t(\"(\")," ++ argList.join(", ") ++ ", t(\")\"),"; + snippet = "t(\"%\"),".format(className) ++ argList; + + // Not sure why this is necessary but some snippets generate new lines? + snippet = snippet.replace(Char.nl, ""); + + }, { + // UltiSnips, Snippets.nvim + argList = signature[index..]; + argList = argList.replace("(", "").replace(")", ""); + argList = argList.split($,); + argList = argList.collect {|a, i| + "${%:%}".format(i+1, a) + }; + argList = "(" ++ argList.join(", ") ++ ")"; + snippet = className ++ argList; + + }); + + case + {snippetFormat == "ultisnips"} { + snippet = "snippet %\n%\nendsnippet\n".format(snippetName, snippet); + } + {snippetFormat == "snippets.nvim"} { + snippet = "['%'] = [[%]];\n".format(snippetName, snippet); + } + {snippetFormat == "luasnip"} { + description = "Snippet for %, auto generated by SCNvim".format(snippetName); + snippet = "s( {trig = \"%\", name = \"%\", dscr = \"%\" }, {%}),".format(snippetName, snippetName, description, snippet); + }; + snippets = snippets.add(snippet ++ Char.nl); + }; + }; + }; + }; + + case + {snippetFormat == "ultisnips"} { + file.write("# SuperCollider snippets" ++ Char.nl); + file.write("# Snippet generator: SCNvim.sc" ++ Char.nl); + file.putAll(snippets); + } + {snippetFormat == "luasnip"} { + file.write("-- SuperCollider snippets for LuaSnip" ++ Char.nl); + file.write("-- Snippet generator: SCNvim.sc" ++ Char.nl); + file.write("local ls = require'luasnip'" ++ Char.nl); + file.write("local s = ls.snippet " ++ Char.nl); + file.write("local i = ls.insert_node" ++ Char.nl); + file.write("local t = ls.text_node" ++ Char.nl); + file.write("local snippets = {" ++ Char.nl); + file.putAll(snippets); + file.write("}" ++ Char.nl); + file.write("return snippets"); + } + {snippetFormat == "snippets.nvim" } { + file.write("-- SuperCollider snippets for Snippets.nvim" ++ Char.nl); + file.write("-- Snippet generator: SCNvim.sc" ++ Char.nl); + file.write("local snippets = {" ++ Char.nl); + file.putAll(snippets); + file.write("}" ++ Char.nl); + file.write("return snippets"); + }; + file.close; + "Generated snippets file: %".format(path).postln; + } } diff --git a/scide_scnvim/Classes/SCNvimDoc/SCNvimDoc.sc b/scide_scnvim/Classes/SCNvimDoc/SCNvimDoc.sc index caad842c..aee1a55a 100644 --- a/scide_scnvim/Classes/SCNvimDoc/SCNvimDoc.sc +++ b/scide_scnvim/Classes/SCNvimDoc/SCNvimDoc.sc @@ -1,15 +1,15 @@ SCNvimDoc : SCDoc { *exportDocMapJson {|path| - var f, numItems; - f = File.open(path,"w"); - numItems = this.documents.size - 1; - f << "{\n"; - this.documents.do {|doc, i| - doc.toJSON(f, i >= numItems); - }; - f << "}\n"; - f.close; - } + var f, numItems; + f = File.open(path,"w"); + numItems = this.documents.size - 1; + f << "{\n"; + this.documents.do {|doc, i| + doc.toJSON(f, i >= numItems); + }; + f << "}\n"; + f.close; + } *parseFileMetaData {|dir,path| var fullPath = dir +/+ path; @@ -115,94 +115,94 @@ SCNvimDoc : SCDoc { }; if(str.last == $_) { str = str.drop(-1) }; - ^str; + ^str; } - *prepareHelpForURL {|url| - var path, targetBasePath, pathIsCaseInsensitive; - var subtarget, src, c, cmd, doc, destExist, destMtime; - var verpath = this.helpTargetDir +/+ "version"; - path = url.asLocalPath; + *prepareHelpForURL {|url| + var path, targetBasePath, pathIsCaseInsensitive; + var subtarget, src, c, cmd, doc, destExist, destMtime; + var verpath = this.helpTargetDir +/+ "version"; + path = url.asLocalPath; - // detect old helpfiles and wrap them in OldHelpWrapper - if(url.scheme == "sc") { ^URI(SCNvimDoc.findHelpFile(path)); }; + // detect old helpfiles and wrap them in OldHelpWrapper + if(url.scheme == "sc") { ^URI(SCNvimDoc.findHelpFile(path)); }; - // just pass through remote url's - if(url.scheme != "file") {^url}; + // just pass through remote url's + if(url.scheme != "file") {^url}; - targetBasePath = SCDoc.helpTargetDir; - if (thisProcess.platform.name === \windows) - { targetBasePath = targetBasePath.replace("/","\\") }; - pathIsCaseInsensitive = thisProcess.platform.name === \windows; + targetBasePath = SCDoc.helpTargetDir; + if (thisProcess.platform.name === \windows) + { targetBasePath = targetBasePath.replace("/","\\") }; + pathIsCaseInsensitive = thisProcess.platform.name === \windows; - // detect old helpfiles and wrap them in OldHelpWrapper - if( - /* - // this didn't work for quarks due to difference between registered old help path and the quarks symlink in Extensions. - // we could use File.realpath(path) below but that would double the execution time, - // so let's just assume any local file outside helpTargetDir is an old helpfile. - block{|break| - Help.do {|key, path| - if(url.endsWith(path)) { - break.value(true) - } - }; false - }*/ - compare( - path [..(targetBasePath.size-1)], - targetBasePath, - pathIsCaseInsensitive - ) != 0 - ) { - ^SCDoc.getOldWrapUrl(url) - }; + // detect old helpfiles and wrap them in OldHelpWrapper + if( + /* + // this didn't work for quarks due to difference between registered old help path and the quarks symlink in Extensions. + // we could use File.realpath(path) below but that would double the execution time, + // so let's just assume any local file outside helpTargetDir is an old helpfile. + block{|break| + Help.do {|key, path| + if(url.endsWith(path)) { + break.value(true) + } + }; false + }*/ + compare( + path [..(targetBasePath.size-1)], + targetBasePath, + pathIsCaseInsensitive + ) != 0 + ) { + ^SCDoc.getOldWrapUrl(url) + }; - if(destExist = File.exists(path)) - { - destMtime = File.mtime(path); - }; + if(destExist = File.exists(path)) + { + destMtime = File.mtime(path); + }; - if(path.endsWith(".html.scnvim")) { - subtarget = path.drop(this.helpTargetDir.size+1).drop(-12).replace("\\","/"); - doc = this.documents[subtarget]; - doc !? { - if(doc.isUndocumentedClass) { - if(doc.mtime == 0) { - this.renderUndocClass(doc); - doc.mtime = 1; - }; - ^url; - }; - if(File.mtime(doc.fullPath)>doc.mtime) { // src changed after indexing - this.postMsg("% changed, re-indexing documents".format(doc.path),2); - this.indexAllDocuments; - ^this.prepareHelpForURL(url); - }; - if(destExist.not - or: {doc.mtime>destMtime} - or: {doc.additions.detect {|f| File.mtime(f)>destMtime}.notNil} - or: {File.mtime(this.helpTargetDir +/+ "scdoc_version")>destMtime} - or: {doc.klass.notNil and: {File.mtime(doc.klass.filenameSymbol.asString)>destMtime}} - ) { - this.parseAndRender(doc); - }; - ^url; - }; - }; + if(path.endsWith(".html.scnvim")) { + subtarget = path.drop(this.helpTargetDir.size+1).drop(-12).replace("\\","/"); + doc = this.documents[subtarget]; + doc !? { + if(doc.isUndocumentedClass) { + if(doc.mtime == 0) { + this.renderUndocClass(doc); + doc.mtime = 1; + }; + ^url; + }; + if(File.mtime(doc.fullPath)>doc.mtime) { // src changed after indexing + this.postMsg("% changed, re-indexing documents".format(doc.path),2); + this.indexAllDocuments; + ^this.prepareHelpForURL(url); + }; + if(destExist.not + or: {doc.mtime>destMtime} + or: {doc.additions.detect {|f| File.mtime(f)>destMtime}.notNil} + or: {File.mtime(this.helpTargetDir +/+ "scdoc_version")>destMtime} + or: {doc.klass.notNil and: {File.mtime(doc.klass.filenameSymbol.asString)>destMtime}} + ) { + this.parseAndRender(doc); + }; + ^url; + }; + }; - if(destExist) { - ^url; - }; + if(destExist) { + ^url; + }; - warn("SCDoc: Broken link:" + url.asString); - ^nil; - } + warn("SCDoc: Broken link:" + url.asString); + ^nil; + } } SCNvimDocEntry : SCDocEntry { destPath { - ^SCDoc.helpTargetDir +/+ path ++ ".html.scnvim"; + ^SCDoc.helpTargetDir +/+ path ++ ".html.scnvim"; } makeMethodList { @@ -234,17 +234,16 @@ SCNvimDocEntry : SCDocEntry { } // overriden to output valid json - prJSONList {|stream, key, v, lastItem| - var delimiter = if(lastItem.notNil and:{lastItem}, "", ","); + prJSONList {|stream, key, v| if (v.isNil) { v = "" }; - stream << "\"" << key << "\": [ " << v.collect{|x|"\""++x.escapeChar(34.asAscii)++"\""}.join(",") << " ]%\n".format(delimiter); + stream << "\"" << key << "\": [ " << v.collect{|x|"\""++x.escapeChar(34.asAscii)++"\""}.join(",") << " ],\n"; } toJSON {|stream, lastItem| var delimiter = if(lastItem.notNil and:{lastItem}, "", ","); var inheritance = []; var numItems; - var keys; + var keys; stream << "\"" << path.escapeChar(34.asAscii) << "\": {\n"; @@ -262,28 +261,24 @@ SCNvimDocEntry : SCDocEntry { this.prJSONString(stream, "oldhelp", oldHelp); }; - if (klass.notNil) { - keys = #[ "superclasses", "subclasses", "implementor" ]; + if(klass.notNil) { klass.superclasses !? { - inheritance = inheritance.add(klass.superclasses.collect {|c| + this.prJSONList(stream, "superclasses", klass.superclasses.collect {|c| c.name.asString - }); + }) }; klass.subclasses !? { - inheritance = inheritance.add(klass.subclasses.collect {|c| + this.prJSONList(stream, "subclasses", klass.subclasses.collect {|c| c.name.asString - }); + }) }; implKlass !? { - inheritance = inheritance.add(implKlass.name.asString); - }; - - numItems = inheritance.size - 1; - inheritance.do {|item, i| - this.prJSONList(stream, keys[i], item, i >= numItems); - }; + this.prJSONString(stream, "implementor", implKlass.name.asString); + } }; - stream << "}%\n".format(delimiter); + stream.seek(-2, 1); + + stream << "\n}%\n".format(delimiter); } } From 14b5d1492b727cbceddb830f24ed811b3fdff8dd Mon Sep 17 00:00:00 2001 From: sadguitarius Date: Fri, 22 May 2026 13:02:31 -0700 Subject: [PATCH 3/4] match tab character placement to upstream --- scide_scnvim/Classes/SCNvim.sc | 546 ++++++++++---------- scide_scnvim/Classes/SCNvimDoc/SCNvimDoc.sc | 168 +++--- 2 files changed, 357 insertions(+), 357 deletions(-) diff --git a/scide_scnvim/Classes/SCNvim.sc b/scide_scnvim/Classes/SCNvim.sc index fa8bcca4..34d6c044 100644 --- a/scide_scnvim/Classes/SCNvim.sc +++ b/scide_scnvim/Classes/SCNvim.sc @@ -1,275 +1,275 @@ SCNvim { - classvar <>netAddr; - classvar <>currentPath; - classvar <>port; - - *sendJSON {|data| - var json; - if (netAddr.isNil) { - netAddr = NetAddr("127.0.0.1", SCNvim.port); - }; - json = SCNvimJSON.stringify(data); - if (json.notNil) { - netAddr.sendRaw(json); - } { - "[scnvim] could not encode to json: %".format(data).warn; - } - } - - *luaeval{|luacode| - SCNvim.sendJSON((action: "luaeval", args: luacode)) - } - - *eval {|expr, callback_id| - var result = expr.interpret; - result = (action: "eval", args: (result: result, id: callback_id)); - SCNvim.sendJSON(result); - } - - *updateStatusLine {arg interval=1; - var stlFunc = { - var serverStatus, data; - var peakCPU, avgCPU, numUGens, numSynths; - var server = Server.default; - var cmd; - if (server.serverRunning) { - peakCPU = server.peakCPU.trunc(0.01); - avgCPU = server.avgCPU.trunc(0.01); - numUGens = "%u".format(server.numUGens); - numSynths = "%s".format(server.numSynths); - serverStatus = "%\\% %\\% % %".format( - peakCPU, avgCPU, numUGens, numSynths - ); - cmd = "require'scnvim.statusline'.set_server_status('%')".format(serverStatus); - SCNvim.luaeval(cmd); - } - }; - SkipJack(stlFunc, interval, name: "scnvim_statusline"); - } - - *generateAssets {|cacheDir, snippetFormat = "ultisnips"| - var tagsPath = cacheDir +/+ "tags"; - var syntaxPath = cacheDir +/+ "classes.vim"; - var snippetPath = cacheDir; - case - {snippetFormat == "ultisnips"} - { - snippetPath = snippetPath +/+ "supercollider.snippets"; - } - {snippetFormat == "snippets.nvim" or: { snippetFormat == "luasnip" }} - { - snippetPath = snippetPath +/+ "scnvim_snippets.lua"; - } - { - "Unrecognized snippet format: '%'".format(snippetFormat).warn; - snippetPath = nil; - }; - Routine.run { - SCNvim.generateTags(tagsPath); - SCNvim.generateSyntax(syntaxPath); - if (snippetPath.notNil) { - SCNvim.generateSnippets(snippetPath, snippetFormat); - } - }; - } - - *generateSyntax {arg outputPath; - var path, file, classes; - classes = Class.allClasses.collect {|class| - class.asString ++ " "; - }; - path = outputPath.standardizePath; - file = File.open(path, "w"); - file.write("syn keyword scObject "); - file.putAll(classes); - file.close; - "Generated syntax file: %".format(path).postln; - } - - // copied from SCVim.sc - // modified to produce a sorted tags file - // GPLv3 license - *generateTags {arg outputPath; - var tagPath, tagFile; - var tags = []; - - tagPath = outputPath ? "~/.sctags"; - tagPath = tagPath.standardizePath; - - tagFile = File.open(tagPath, "w"); - - tagFile.write('!_TAG_FILE_FORMAT 2 /extended format; --format=1 will not append ;" to lines/'.asString ++ Char.nl); - tagFile.write("!_TAG_FILE_SORTED 1 /0=unsorted, 1=sorted, 2=foldcase/" ++ Char.nl); - tagFile.write("!_TAG_PROGRAM_AUTHOR Stephen Lumenta /stephen.lumenta@gmail.com/" ++ Char.nl); - tagFile.write("!_TAG_PROGRAM_NAME SCNVim.sc//" ++ Char.nl); - tagFile.write("!_TAG_PROGRAM_URL https://github.com/davidgranstrom/scnvim" ++ Char.nl); - tagFile.write("!_TAG_PROGRAM_VERSION 2.0//" ++ Char.nl); - - Class.allClasses.do {arg klass; - var klassName, klassFilename, klassSearchString; - var result; - - klassName = klass.asString; - klassFilename = klass.filenameSymbol; - // use a symbol and convert to string to avoid the "open ended - // string" error on class lib compiliation - klassSearchString = '/^%/;"%%'.asString.format(klassName, Char.tab, "c"); - - result = klassName ++ Char.tab ++ klassFilename ++ Char.tab ++ klassSearchString ++ Char.nl; - tags = tags.add(result); - - klass.methods.do {arg meth; - var methName, methFilename, methSearchString; - methName = meth.name; - methFilename = meth.filenameSymbol; - methSearchString = '/% {/;"%%'.asString.format(methName, Char.tab, "m"); - result = methName ++ Char.tab ++ methFilename ++ Char.tab ++ methSearchString ++ Char.nl; - tags = tags.add(result); - } - }; - - tags = tags.sort; - tagFile.putAll(tags); - tagFile.close; - "Generated tags file: %".format(tagPath).postln; - } - - *generateSnippets {arg outputPath, snippetFormat; - var file, path; - var snippets = []; - - path = outputPath ? "~/.scsnippets"; - path = path.standardizePath; - file = File.open(path, "w"); - snippetFormat = snippetFormat ? "ultisnips"; - - Class.allClasses.do {arg klass; - var className, argList, signature; - if (klass.asString.beginsWith("Meta_").not) { - var currClass = klass; - // get methods from superclass for derived classes - // TODO: should traverse entire heirarchy but this produces too many snippets! - while ({currClass.class.methods.isNil}, { - currClass = currClass.superclass; - }); - // collect all creation methods - currClass.class.methods.do {arg meth; - var index, snippet; - var snippetName; - var description; - // classvars with getter/setters produces an error - // since we're only interested in creation methods we skip them - try { - snippetName = "%.%".format(klass, meth.name); - signature = Help.methodArgs(snippetName); - }; - - if (signature.notNil and:{signature.isEmpty.not}) { - index = signature.find("("); - className = signature[..index - 1]; - className = className.replace("*", ".").replace(" ", ""); - - if(snippetFormat == "luasnip", { - - // LuaSnip - argList = signature[index..]; - argList = argList.replace("(", "").replace(")", ""); - argList = argList.split($,); - argList = argList.collect {|a, i| - var scArg = a.replace(" ", "").split($:); - var scArgName = scArg[0]; - var scArgVal = scArg[1]; - var snipArgument; - var escapeChars; - - // Create argument name as text node - snipArgument = "t(\"%:\"),".format(scArgName); - - // Escape all characters that might break the snippet - escapeChars = [ - $\\, - $", - $', - ]; - - escapeChars.do {|char| - scArgVal = scArgVal.asString.replace(char, "\\" ++ char.asString); - }; - - // Create argument default value as insert node - snipArgument = snipArgument ++ "i(%, %)".format(i+1, scArgVal.quote); - - // Only add text node with comma if not last item - if(i+1 != argList.size, { - snipArgument = snipArgument ++ ",t(\", \")" - }); - - snipArgument - }; - - argList = "t(\"(\")," ++ argList.join(", ") ++ ", t(\")\"),"; - snippet = "t(\"%\"),".format(className) ++ argList; - - // Not sure why this is necessary but some snippets generate new lines? - snippet = snippet.replace(Char.nl, ""); - - }, { - // UltiSnips, Snippets.nvim - argList = signature[index..]; - argList = argList.replace("(", "").replace(")", ""); - argList = argList.split($,); - argList = argList.collect {|a, i| - "${%:%}".format(i+1, a) - }; - argList = "(" ++ argList.join(", ") ++ ")"; - snippet = className ++ argList; - - }); - - case - {snippetFormat == "ultisnips"} { - snippet = "snippet %\n%\nendsnippet\n".format(snippetName, snippet); - } - {snippetFormat == "snippets.nvim"} { - snippet = "['%'] = [[%]];\n".format(snippetName, snippet); - } - {snippetFormat == "luasnip"} { - description = "Snippet for %, auto generated by SCNvim".format(snippetName); - snippet = "s( {trig = \"%\", name = \"%\", dscr = \"%\" }, {%}),".format(snippetName, snippetName, description, snippet); - }; - snippets = snippets.add(snippet ++ Char.nl); - }; - }; - }; - }; - - case - {snippetFormat == "ultisnips"} { - file.write("# SuperCollider snippets" ++ Char.nl); - file.write("# Snippet generator: SCNvim.sc" ++ Char.nl); - file.putAll(snippets); - } - {snippetFormat == "luasnip"} { - file.write("-- SuperCollider snippets for LuaSnip" ++ Char.nl); - file.write("-- Snippet generator: SCNvim.sc" ++ Char.nl); - file.write("local ls = require'luasnip'" ++ Char.nl); - file.write("local s = ls.snippet " ++ Char.nl); - file.write("local i = ls.insert_node" ++ Char.nl); - file.write("local t = ls.text_node" ++ Char.nl); - file.write("local snippets = {" ++ Char.nl); - file.putAll(snippets); - file.write("}" ++ Char.nl); - file.write("return snippets"); - } - {snippetFormat == "snippets.nvim" } { - file.write("-- SuperCollider snippets for Snippets.nvim" ++ Char.nl); - file.write("-- Snippet generator: SCNvim.sc" ++ Char.nl); - file.write("local snippets = {" ++ Char.nl); - file.putAll(snippets); - file.write("}" ++ Char.nl); - file.write("return snippets"); - }; - file.close; - "Generated snippets file: %".format(path).postln; - } + classvar <>netAddr; + classvar <>currentPath; + classvar <>port; + + *sendJSON {|data| + var json; + if (netAddr.isNil) { + netAddr = NetAddr("127.0.0.1", SCNvim.port); + }; + json = SCNvimJSON.stringify(data); + if (json.notNil) { + netAddr.sendRaw(json); + } { + "[scnvim] could not encode to json: %".format(data).warn; + } + } + + *luaeval{|luacode| + SCNvim.sendJSON((action: "luaeval", args: luacode)) + } + + *eval {|expr, callback_id| + var result = expr.interpret; + result = (action: "eval", args: (result: result, id: callback_id)); + SCNvim.sendJSON(result); + } + + *updateStatusLine {arg interval=1; + var stlFunc = { + var serverStatus, data; + var peakCPU, avgCPU, numUGens, numSynths; + var server = Server.default; + var cmd; + if (server.serverRunning) { + peakCPU = server.peakCPU.trunc(0.01); + avgCPU = server.avgCPU.trunc(0.01); + numUGens = "%u".format(server.numUGens); + numSynths = "%s".format(server.numSynths); + serverStatus = "%\\% %\\% % %".format( + peakCPU, avgCPU, numUGens, numSynths + ); + cmd = "require'scnvim.statusline'.set_server_status('%')".format(serverStatus); + SCNvim.luaeval(cmd); + } + }; + SkipJack(stlFunc, interval, name: "scnvim_statusline"); + } + + *generateAssets {|cacheDir, snippetFormat = "ultisnips"| + var tagsPath = cacheDir +/+ "tags"; + var syntaxPath = cacheDir +/+ "classes.vim"; + var snippetPath = cacheDir; + case + {snippetFormat == "ultisnips"} + { + snippetPath = snippetPath +/+ "supercollider.snippets"; + } + {snippetFormat == "snippets.nvim" or: { snippetFormat == "luasnip" }} + { + snippetPath = snippetPath +/+ "scnvim_snippets.lua"; + } + { + "Unrecognized snippet format: '%'".format(snippetFormat).warn; + snippetPath = nil; + }; + Routine.run { + SCNvim.generateTags(tagsPath); + SCNvim.generateSyntax(syntaxPath); + if (snippetPath.notNil) { + SCNvim.generateSnippets(snippetPath, snippetFormat); + } + }; + } + + *generateSyntax {arg outputPath; + var path, file, classes; + classes = Class.allClasses.collect {|class| + class.asString ++ " "; + }; + path = outputPath.standardizePath; + file = File.open(path, "w"); + file.write("syn keyword scObject "); + file.putAll(classes); + file.close; + "Generated syntax file: %".format(path).postln; + } + + // copied from SCVim.sc + // modified to produce a sorted tags file + // GPLv3 license + *generateTags {arg outputPath; + var tagPath, tagFile; + var tags = []; + + tagPath = outputPath ? "~/.sctags"; + tagPath = tagPath.standardizePath; + + tagFile = File.open(tagPath, "w"); + + tagFile.write('!_TAG_FILE_FORMAT 2 /extended format; --format=1 will not append ;" to lines/'.asString ++ Char.nl); + tagFile.write("!_TAG_FILE_SORTED 1 /0=unsorted, 1=sorted, 2=foldcase/" ++ Char.nl); + tagFile.write("!_TAG_PROGRAM_AUTHOR Stephen Lumenta /stephen.lumenta@gmail.com/" ++ Char.nl); + tagFile.write("!_TAG_PROGRAM_NAME SCNVim.sc//" ++ Char.nl); + tagFile.write("!_TAG_PROGRAM_URL https://github.com/davidgranstrom/scnvim" ++ Char.nl); + tagFile.write("!_TAG_PROGRAM_VERSION 2.0//" ++ Char.nl); + + Class.allClasses.do {arg klass; + var klassName, klassFilename, klassSearchString; + var result; + + klassName = klass.asString; + klassFilename = klass.filenameSymbol; + // use a symbol and convert to string to avoid the "open ended + // string" error on class lib compiliation + klassSearchString = '/^%/;"%%'.asString.format(klassName, Char.tab, "c"); + + result = klassName ++ Char.tab ++ klassFilename ++ Char.tab ++ klassSearchString ++ Char.nl; + tags = tags.add(result); + + klass.methods.do {arg meth; + var methName, methFilename, methSearchString; + methName = meth.name; + methFilename = meth.filenameSymbol; + methSearchString = '/% {/;"%%'.asString.format(methName, Char.tab, "m"); + result = methName ++ Char.tab ++ methFilename ++ Char.tab ++ methSearchString ++ Char.nl; + tags = tags.add(result); + } + }; + + tags = tags.sort; + tagFile.putAll(tags); + tagFile.close; + "Generated tags file: %".format(tagPath).postln; + } + + *generateSnippets {arg outputPath, snippetFormat; + var file, path; + var snippets = []; + + path = outputPath ? "~/.scsnippets"; + path = path.standardizePath; + file = File.open(path, "w"); + snippetFormat = snippetFormat ? "ultisnips"; + + Class.allClasses.do {arg klass; + var className, argList, signature; + if (klass.asString.beginsWith("Meta_").not) { + var currClass = klass; + // get methods from superclass for derived classes + // TODO: should traverse entire heirarchy but this produces too many snippets! + while ({currClass.class.methods.isNil}, { + currClass = currClass.superclass; + }); + // collect all creation methods + currClass.class.methods.do {arg meth; + var index, snippet; + var snippetName; + var description; + // classvars with getter/setters produces an error + // since we're only interested in creation methods we skip them + try { + snippetName = "%.%".format(klass, meth.name); + signature = Help.methodArgs(snippetName); + }; + + if (signature.notNil and:{signature.isEmpty.not}) { + index = signature.find("("); + className = signature[..index - 1]; + className = className.replace("*", ".").replace(" ", ""); + + if(snippetFormat == "luasnip", { + + // LuaSnip + argList = signature[index..]; + argList = argList.replace("(", "").replace(")", ""); + argList = argList.split($,); + argList = argList.collect {|a, i| + var scArg = a.replace(" ", "").split($:); + var scArgName = scArg[0]; + var scArgVal = scArg[1]; + var snipArgument; + var escapeChars; + + // Create argument name as text node + snipArgument = "t(\"%:\"),".format(scArgName); + + // Escape all characters that might break the snippet + escapeChars = [ + $\\, + $", + $', + ]; + + escapeChars.do {|char| + scArgVal = scArgVal.asString.replace(char, "\\" ++ char.asString); + }; + + // Create argument default value as insert node + snipArgument = snipArgument ++ "i(%, %)".format(i+1, scArgVal.quote); + + // Only add text node with comma if not last item + if(i+1 != argList.size, { + snipArgument = snipArgument ++ ",t(\", \")" + }); + + snipArgument + }; + + argList = "t(\"(\")," ++ argList.join(", ") ++ ", t(\")\"),"; + snippet = "t(\"%\"),".format(className) ++ argList; + + // Not sure why this is necessary but some snippets generate new lines? + snippet = snippet.replace(Char.nl, ""); + + }, { + // UltiSnips, Snippets.nvim + argList = signature[index..]; + argList = argList.replace("(", "").replace(")", ""); + argList = argList.split($,); + argList = argList.collect {|a, i| + "${%:%}".format(i+1, a) + }; + argList = "(" ++ argList.join(", ") ++ ")"; + snippet = className ++ argList; + + }); + + case + {snippetFormat == "ultisnips"} { + snippet = "snippet %\n%\nendsnippet\n".format(snippetName, snippet); + } + {snippetFormat == "snippets.nvim"} { + snippet = "['%'] = [[%]];\n".format(snippetName, snippet); + } + {snippetFormat == "luasnip"} { + description = "Snippet for %, auto generated by SCNvim".format(snippetName); + snippet = "s( {trig = \"%\", name = \"%\", dscr = \"%\" }, {%}),".format(snippetName, snippetName, description, snippet); + }; + snippets = snippets.add(snippet ++ Char.nl); + }; + }; + }; + }; + + case + {snippetFormat == "ultisnips"} { + file.write("# SuperCollider snippets" ++ Char.nl); + file.write("# Snippet generator: SCNvim.sc" ++ Char.nl); + file.putAll(snippets); + } + {snippetFormat == "luasnip"} { + file.write("-- SuperCollider snippets for LuaSnip" ++ Char.nl); + file.write("-- Snippet generator: SCNvim.sc" ++ Char.nl); + file.write("local ls = require'luasnip'" ++ Char.nl); + file.write("local s = ls.snippet " ++ Char.nl); + file.write("local i = ls.insert_node" ++ Char.nl); + file.write("local t = ls.text_node" ++ Char.nl); + file.write("local snippets = {" ++ Char.nl); + file.putAll(snippets); + file.write("}" ++ Char.nl); + file.write("return snippets"); + } + {snippetFormat == "snippets.nvim" } { + file.write("-- SuperCollider snippets for Snippets.nvim" ++ Char.nl); + file.write("-- Snippet generator: SCNvim.sc" ++ Char.nl); + file.write("local snippets = {" ++ Char.nl); + file.putAll(snippets); + file.write("}" ++ Char.nl); + file.write("return snippets"); + }; + file.close; + "Generated snippets file: %".format(path).postln; + } } diff --git a/scide_scnvim/Classes/SCNvimDoc/SCNvimDoc.sc b/scide_scnvim/Classes/SCNvimDoc/SCNvimDoc.sc index aee1a55a..a98060b7 100644 --- a/scide_scnvim/Classes/SCNvimDoc/SCNvimDoc.sc +++ b/scide_scnvim/Classes/SCNvimDoc/SCNvimDoc.sc @@ -1,15 +1,15 @@ SCNvimDoc : SCDoc { *exportDocMapJson {|path| - var f, numItems; - f = File.open(path,"w"); - numItems = this.documents.size - 1; - f << "{\n"; - this.documents.do {|doc, i| - doc.toJSON(f, i >= numItems); - }; - f << "}\n"; - f.close; - } + var f, numItems; + f = File.open(path,"w"); + numItems = this.documents.size - 1; + f << "{\n"; + this.documents.do {|doc, i| + doc.toJSON(f, i >= numItems); + }; + f << "}\n"; + f.close; + } *parseFileMetaData {|dir,path| var fullPath = dir +/+ path; @@ -115,94 +115,94 @@ SCNvimDoc : SCDoc { }; if(str.last == $_) { str = str.drop(-1) }; - ^str; + ^str; } - *prepareHelpForURL {|url| - var path, targetBasePath, pathIsCaseInsensitive; - var subtarget, src, c, cmd, doc, destExist, destMtime; - var verpath = this.helpTargetDir +/+ "version"; - path = url.asLocalPath; + *prepareHelpForURL {|url| + var path, targetBasePath, pathIsCaseInsensitive; + var subtarget, src, c, cmd, doc, destExist, destMtime; + var verpath = this.helpTargetDir +/+ "version"; + path = url.asLocalPath; - // detect old helpfiles and wrap them in OldHelpWrapper - if(url.scheme == "sc") { ^URI(SCNvimDoc.findHelpFile(path)); }; + // detect old helpfiles and wrap them in OldHelpWrapper + if(url.scheme == "sc") { ^URI(SCNvimDoc.findHelpFile(path)); }; - // just pass through remote url's - if(url.scheme != "file") {^url}; + // just pass through remote url's + if(url.scheme != "file") {^url}; - targetBasePath = SCDoc.helpTargetDir; - if (thisProcess.platform.name === \windows) - { targetBasePath = targetBasePath.replace("/","\\") }; - pathIsCaseInsensitive = thisProcess.platform.name === \windows; + targetBasePath = SCDoc.helpTargetDir; + if (thisProcess.platform.name === \windows) + { targetBasePath = targetBasePath.replace("/","\\") }; + pathIsCaseInsensitive = thisProcess.platform.name === \windows; - // detect old helpfiles and wrap them in OldHelpWrapper - if( - /* - // this didn't work for quarks due to difference between registered old help path and the quarks symlink in Extensions. - // we could use File.realpath(path) below but that would double the execution time, - // so let's just assume any local file outside helpTargetDir is an old helpfile. - block{|break| - Help.do {|key, path| - if(url.endsWith(path)) { - break.value(true) - } - }; false - }*/ - compare( - path [..(targetBasePath.size-1)], - targetBasePath, - pathIsCaseInsensitive - ) != 0 - ) { - ^SCDoc.getOldWrapUrl(url) - }; + // detect old helpfiles and wrap them in OldHelpWrapper + if( + /* + // this didn't work for quarks due to difference between registered old help path and the quarks symlink in Extensions. + // we could use File.realpath(path) below but that would double the execution time, + // so let's just assume any local file outside helpTargetDir is an old helpfile. + block{|break| + Help.do {|key, path| + if(url.endsWith(path)) { + break.value(true) + } + }; false + }*/ + compare( + path [..(targetBasePath.size-1)], + targetBasePath, + pathIsCaseInsensitive + ) != 0 + ) { + ^SCDoc.getOldWrapUrl(url) + }; - if(destExist = File.exists(path)) - { - destMtime = File.mtime(path); - }; + if(destExist = File.exists(path)) + { + destMtime = File.mtime(path); + }; - if(path.endsWith(".html.scnvim")) { - subtarget = path.drop(this.helpTargetDir.size+1).drop(-12).replace("\\","/"); - doc = this.documents[subtarget]; - doc !? { - if(doc.isUndocumentedClass) { - if(doc.mtime == 0) { - this.renderUndocClass(doc); - doc.mtime = 1; - }; - ^url; - }; - if(File.mtime(doc.fullPath)>doc.mtime) { // src changed after indexing - this.postMsg("% changed, re-indexing documents".format(doc.path),2); - this.indexAllDocuments; - ^this.prepareHelpForURL(url); - }; - if(destExist.not - or: {doc.mtime>destMtime} - or: {doc.additions.detect {|f| File.mtime(f)>destMtime}.notNil} - or: {File.mtime(this.helpTargetDir +/+ "scdoc_version")>destMtime} - or: {doc.klass.notNil and: {File.mtime(doc.klass.filenameSymbol.asString)>destMtime}} - ) { - this.parseAndRender(doc); - }; - ^url; - }; - }; + if(path.endsWith(".html.scnvim")) { + subtarget = path.drop(this.helpTargetDir.size+1).drop(-12).replace("\\","/"); + doc = this.documents[subtarget]; + doc !? { + if(doc.isUndocumentedClass) { + if(doc.mtime == 0) { + this.renderUndocClass(doc); + doc.mtime = 1; + }; + ^url; + }; + if(File.mtime(doc.fullPath)>doc.mtime) { // src changed after indexing + this.postMsg("% changed, re-indexing documents".format(doc.path),2); + this.indexAllDocuments; + ^this.prepareHelpForURL(url); + }; + if(destExist.not + or: {doc.mtime>destMtime} + or: {doc.additions.detect {|f| File.mtime(f)>destMtime}.notNil} + or: {File.mtime(this.helpTargetDir +/+ "scdoc_version")>destMtime} + or: {doc.klass.notNil and: {File.mtime(doc.klass.filenameSymbol.asString)>destMtime}} + ) { + this.parseAndRender(doc); + }; + ^url; + }; + }; - if(destExist) { - ^url; - }; + if(destExist) { + ^url; + }; - warn("SCDoc: Broken link:" + url.asString); - ^nil; - } + warn("SCDoc: Broken link:" + url.asString); + ^nil; + } } SCNvimDocEntry : SCDocEntry { destPath { - ^SCDoc.helpTargetDir +/+ path ++ ".html.scnvim"; + ^SCDoc.helpTargetDir +/+ path ++ ".html.scnvim"; } makeMethodList { @@ -243,7 +243,7 @@ SCNvimDocEntry : SCDocEntry { var delimiter = if(lastItem.notNil and:{lastItem}, "", ","); var inheritance = []; var numItems; - var keys; + var keys; stream << "\"" << path.escapeChar(34.asAscii) << "\": {\n"; From acc962ef0ef2fd2590921a467590ee5558f33dbf Mon Sep 17 00:00:00 2001 From: sadguitarius Date: Fri, 22 May 2026 13:35:24 -0700 Subject: [PATCH 4/4] fix formatting --- lua/scnvim/config.lua | 2 +- lua/scnvim/editor.lua | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/lua/scnvim/config.lua b/lua/scnvim/config.lua index ff6ab114..012e78fa 100644 --- a/lua/scnvim/config.lua +++ b/lua/scnvim/config.lua @@ -100,7 +100,7 @@ local default = { border = 'single', }, callback = function(id) - vim.api.nvim_set_option_value('winblend', 10, {win = id}) + vim.api.nvim_set_option_value('winblend', 10, { win = id }) end, }, }, diff --git a/lua/scnvim/editor.lua b/lua/scnvim/editor.lua index 22e828c2..30a1afbb 100644 --- a/lua/scnvim/editor.lua +++ b/lua/scnvim/editor.lua @@ -116,7 +116,7 @@ local function fade_region(start, finish) anchor = lstart > 0 and 'NW' or 'SE', } local id = api.nvim_open_win(buf, false, options) - api.nvim_set_option_value('winhl', 'Normal:' .. 'SCNvimEval', {win = id}) + api.nvim_set_option_value('winhl', 'Normal:' .. 'SCNvimEval', { win = id }) local timer = uv.new_timer() local rate = 50 local accum = 0 @@ -131,7 +131,7 @@ local function fade_region(start, finish) accum = duration end local value = math.pow(accum / duration, 2.5) - api.nvim_set_option_value('winblend', math.floor(100 * value), {win = id}) + api.nvim_set_option_value('winblend', math.floor(100 * value), { win = id }) if accum >= duration then timer:stop() api.nvim_win_close(id, true)