I find myself wasting a lot of time manually editing SVG icons so I can store them in a json file. Specifically, I need to:
replace " with ’
remove all line endings
replace # with %23
I figured I could create an extension that does just that, but I have no idea where to start. The extension reference is just that - a reference, but I could use some hand holding on how to go about this.
The plugin is a good idea, however, it might be an overkill for your task. Plus your specs and needs might change later, but you’ll be bound to support the plugin forever. For tasks like that, I tend to make tiny self-contained helper apps — single, self-contained HTML file — driven by Vue.js and CodeMirror — which does whatever is needed, quickly. For example, Tokenizer Tap — that’s two fields, input and output, plus dumping into localstorage so that when you refresh, fields are not wiped. Each time it loads, it reads localstorage and restores the dumped values. Each time you edit CodeMirror, it dumps into localstorage. That example is consuming JS package’s UMD build from jsdelivr. Rollup can build UMD’s. But you could remove references to the tokenizer and just put three chained String.prototype.replace(). If you really struggle, I can help you wire all these three tasks for MVP, it’s like 5 minute job, a cheeky tiny Vue app with two CodeMirror fields. Once you have the MVP, you can a) post it online, get the feedback; and/or b) separate the functionality into a standalone npm package, write proper unit tests, gather other maintainers (it’s a challenge to maintain packages) then write Nova’s plugin and tap that package.
hi Roy,
thank you so much for your thoughtful reply. Problem is, I don’t use Vue.js and CodeMirror. My approach to software development is minimalistic - I avoid using/learning new frameworks as much as possible (by the time I have learned them chances are another, even better framework is available. think Next, for example). The suggestion of creating a small web app is compelling, though. I’ll give it a serious thought.
As for the extension: I thought that all it would take is for me to figure out how to read on open document in Nova, do the necessary replacements and save it. But I couldn’t find any information at all on how to even start designing an extension. Is it so much more complicated than the web app idea?
Hi Franco,
I really believe an extension would be overkill for this task. Have you considered using AppleScript?
I made a small script which should do what you want. It opens a file you choose, replaces the characters and saves it (overwriting).
tell application "Finder"
set theFile to choose file
set theFileRef to open for access theFile with write permission
set theContents to read theFileRef
set theContents to my replaceText("\"", "'", theContents)
set theContents to my replaceText(ASCII character 10, "", theContents)
set theContents to my replaceText("#", "%23", theContents)
write theContents to theFileRef starting at 0
close access theFileRef
end tell
on replaceText(needle, replacement, haystack)
set prevTIDs to AppleScript's text item delimiters
set AppleScript's text item delimiters to needle
set textItems to every text item of haystack
set AppleScript's text item delimiters to replacement
set haystack to textItems as string
set AppleScript's text item delimiters to prevTIDs
return haystack
end replaceText
Although I must admit there may be cases where this fails. I don’t know all specs of the SVG file format.
Now Applescript is probably the best approach for my problem. So thank you so much for helping, I really appreciate it.
An SVG document is just a text file, a markup language for vector design.
Replacing the double quotes won’t fail, that’s required by JSON and SVG doesn’t care. Neither removing the EOLs.
Replacing # with %23 is now an ANSI standard requirement for when you want to include an SVG directly as a src attribute i.e. in an img. In theory the entire SVG should be URL-encoded, but in my experience the # is the only character a browser could choke on.
I am not disagreeing with you on the extension question, I simply am curious to learn more about how to create an extension, as the documentation really is of no help. I thought my problem would be a gentle way to get into this area. I hope Panic at some point will provide some kind of introduction to designing extensions.
Here’s the tiny UI, 99 lines incl. comments, two versions (return result1 for regex’es only instead of result2) — it’s two input boxes only, local storage wired for persistence upon refresh, uses proper jsesc - npm for JSON escaping, CSS theme is Oceanic Plus(-ish):
<!DOCTYPE html>
<html lang="en" dir="ltr">
<head>
<meta charset="utf-8" />
<title>SVG Processor</title>
<style type="text/css">
* {
padding: 0;
margin: 0;
font-size: 14px;
color: #f9c76b; /* yellow-ish */
background-color: #1c2c34;
font-family: sans-serif;
}
body {
margin: 0;
overflow-x: hidden;
overflow-y: hidden;
}
textarea {
color: #bec5cf; /* white-ish */
width: 49%;
height: 100vh;
font-family: monospace;
}
</style>
</head>
<body>
<div id="app">
<textarea ref="in" v-model="text1" placeholder="put html here or drag a file"></textarea>
<textarea ref="out" v-model="text2"></textarea>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2.6.12/dist/vue.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/jsesc@3.0.2/jsesc.js"></script>
<script>
Vue.config.productionTip = false;
const myStorage = window.localStorage;
window.Event = new Vue();
new Vue({
el: "#app",
data: {
text1: "",
},
mounted: function () {
console.log(`068 called mounted()`);
const retrieved = myStorage.getItem("svgprocessor");
if (typeof retrieved === "string" && retrieved.length) {
this.text1 = retrieved;
} else {
this.text1 = "";
}
this.$refs.in.focus();
},
computed: {
text2: function () {
// update the "out" text area:
if (typeof this.text1 === "string") {
// version 1 - DIY escaping with replaces:
const result1 = this.text1
.replace(/"/g, "'")
// CR/LF/CRLF line ending regex:
.replace(/(\r?\n)/g, "")
// replace one or more tab with nothing:
.replace(/\t+/g, "")
// replace more than one space with single space:
.replace(/\s+/g, " ")
// DIY-encode hashes:
.replace(/#/g, "%23");
// version 2 - npmjs.com/package/jsesc
const result2 = jsesc(
this.text1
.replace(/(\r?\n)/g, "")
.replace(/\t+/g, ""),
{
json: true,
}
);
return result2; // return result1 alternatively
}
return this.text1 || "";
},
},
watch: {
text1: function () {
console.log(`113 dump to local storage`);
// dump the input into the local storage so you can refresh
if (typeof this.text1 === "string" && this.text1.length) {
myStorage.setItem("svgprocessor", this.text1);
} else {
myStorage.setItem("svgprocessor", "");
}
},
},
});
</script>
</body>
</html>
take it and do whatever you want with it, no attribution needed, I submit it to Public Domain
We’d love to do this! More in-depth, guided tutorials would definitely be a great resource. At the moment, we’ve been constrained by our staff size in terms of expanding our help content (Nova is built, QA’d, and documented by, effectively, a team of five.), but we really hope to be able to improve this going forward as our development milestones relax a bit.
has there been any movement on this? I have tried a number of times to create a very very simple SYNTAX extension to no avail. My test extensions do show in the EXTENSION LIBRARY and are enabled; however the actual SYNTAX doesnt display in the EDITOR / SYNTAX menu, in settings where I can specify a syntax on a file extension nor in the bottom right of the NOVA window. I have been using CODA2 up until recently because of the syntax highlighting there. Any direction towards a step by step or how to make a basic extension would be much appreciated.
Thanks for the response Emran … I have double checked the above and still no luck. I then ‘showed the contents’ of NOVA.APP in FINDER as navigated to Contents/SharedSupport/Extensions and copied the PHP.novaextension to use that as a ‘base template’ to modify. Still no luck.
Are there any dev’s out there that would be happy to do a screen share with me to maybe point me in the right direction or I can show you what I am looking to do and you can quote me to create the extension for me?
EDIT
For any other Newbies out there, the issue of the SYNTAX option not showing as options in Nova was being caused by non escaped XML in some syntaxes, eg:
I can certainly help out if you would like, just ping me the repo and tag me in the issues.
PS: If there is a tree-sitter grammar out there for the language you are trying to implement, I would highly recommend using that instead of RegEx grammars, as it is being phased out prob sometimes in the future.