I want to make a relatively simple formatter in VS Code. Essentially, I have a bunch of *.md.j2 files (Jinja2 templates that ultimately become Markdown). I have the Better Jinja extension to render these, with the language jinja-md in VS Code.
I started off just wanting to use prettier's Markdown formatting and call it a day. I tried adding this to settings.json:
"[jinja-md]": {
"editor.defaultFormatter": "esbenp.prettier-vscode",
"editor.formatOnSave": true,
},
This does not work because esbenp.prettier-vscode does not register itself for the jinja-md type; it seems to have no "break glass" option to configure that.
This got me to thinking that it would be nice to make a formatter that ignored Jinja tag lines (e.g. {% if foo == 'bar' %}\n and then passed on the fragments to whatever the underlying file type formatter was. So basically I want to do something like:
vscode.languages.registerDocumentFormattingEditProvider('jinja-md', {
provideDocumentFormattingEdits(document: vscode.TextDocument): vscode.TextEdit[] {
// THIS IS THE QUESTION:
// vscode.languages.getFormatter is not a real method. I want to know
// how to pull off this concept.
mdFormatter = vscode.languages.getFormatter('md');
// Get segments between %}\n and \n{% and route them to the
// `mdFormatter` -- I think I know how to do this and am not bothering
// to write the code here.
}
});
Is this a thing I can do -- can I programmatically get from VSCode "the formatter user-configured for language X"?
Webpack bundle analyzer shows that icons from bootstrap-vue package are 535kb in size.
I don`t want to use them in a project, so I have been trying to exclude the package with a webpack IgnorePlugin.
According to example in documentation, I have tried to write this:
new webpack.IgnorePlugin({
resourceRegExp: /^icons(.*)$/,
contextRegExp: /^bootstrap-vue(.*)$/
})
but it didn`t work. The only thing I was able to reproduce, is to completely exclude bootstrap-vue lib via this constriction new webpack.IgnorePlugin(/bootstrap-vue/)
So how I can exclude only icons?
Here is the way to ignore the icons from bootstrap-vue:
new webpack.IgnorePlugin({
resourceRegExp: /\/icons\//,
contextRegExp: /bootstrap-vue/,
});
Next time if you are in doubt try to use checkResource function instead, it's easier to write and understand in comparison to regexp:
new webpack.IgnorePlugin({
checkResource (resource, context) {
if (context.includes('bootstrap-vue')) {
console.log(resource, ':::', context)
// check console to figure out how the resource is used
// update the function until it's satisfies your case
// then move to regexp if you wish
}
return false
},
})
But after doing this research it turned out that some components actually use some icons and icons in general are not as big as I expected. Using source of the bootstrap-vue had bigger impact on our bundle. So decided to stick with this approach instead
Prior to Modernizr v3, I was using yepnope.js
Modernizr.load and yepnope.js have both been deprecated. How do we conditionally call stylesheets or javascript files now?
Example that worked with Modernizr v2.5.3:
Modernizr.load({
test: Modernizr['object-fit'],
nope: ['./dist/scripts/object-fit.js'],
complete: function(){
if (!Modernizr['object-fit']) {
jQuery(".poster img").imageScale({
scale: "best-fill",
rescaleOnResize: true
});
}
}
});
There's a new syntax and the feature names are all lowercase. You can combine that with jQuery's getScript method.
Which would look something like this:
if (Modernizr.objectfit){
jQuery.getScript("./dist/scripts/object-fit.js")
//it worked! do something!
.done(function(){
console.log('js loaded');
})
//it didn't work! do something!
.fail(function(){
console.log('js not loaded');
});
} else {
jQuery(".poster img").imageScale({
scale: "best-fill",
rescaleOnResize: true
});
}
Have a look here for scripts: https://stackoverflow.com/a/7719185 — no jQuery required. (Note that there's a shorter Promise example a bit down in the answer; don't stop reading after the first example (like I did)).
And here for CSS: loadCSS: https://github.com/filamentgroup/loadCSS/blob/master/src/loadCSS.js
— this is, in a way, even better than YepNope.js, if you don't need any of its features except for just loading stuff + callback. Because the stuff linked above, is smaller (smaller min.js.gz) than yepnope.js.
(And can combine with Modernizr like mhk showed in his answer.)
If I call:
.somemethod({
&:extend(.flex all);
});
then it appears as if less do not complain but it does generate the appropiate css either.
Is this a bug ? Has it been resolved? I am still on 2014 Java version of less, might need an update if it's worth it.
Edit, added the method somemethod:
.somemethod(#mx){
#mx();
}
.flex {
color:blue;
}
body > main {
.somemethod({
&:extend(.flex all);
});
}
I'm in the process of building my first Safari extension--a very simple one--but I've run into a couple of problems. The extension boils down to a single, injected script that attempts to bypass the native feed handler and redirect to an http:// URI. My issues so far are twofold:
The "whitelist" isn't working the way I'd expect. Since all feeds are shown under the "feed://" protocol, I've tried to capture that in the whitelist as "feed://*/*" (with nothing in the blacklist), but I end up in a request loop that I can't understand. If I set blacklist values of "http://*/*" and "https://*/*", everything works as expected.
I can't figure out how to access my settings from my injected script. The script creates a beforeload event handler, but can't access my settings using the safari.extension.settings path indicated in the documentation.
I haven't found anything in Apple's documentation to indicate that settings shouldn't be available from my script. Since extensions are such a new feature, even Google returns limited relevant results and most of those are from the official documentation.
What am I missing?
UPDATE
So I'm hoping that the documentation is incomplete because it's borderline abysmal, but I've learned a bit about settings. It turns out that, from injection scripts, the SafariExtensionSettings object isn't available. Injection scripts only have access to the SafariContentExtension object (which isn't useful at all), but it's aliased in exactly the same manner (safari.extension.settings)--bad idea, IMO. As stated in the injection script documentation:
Important: When you use safari.extension from within an injected script, you are not addressing the SafariExtension class. You are addressing the SafariContentExtension class.
You have to use the messaging system to talk to a global HTML file which has access to the settings. It's kind of loopy, but I have a message being sent to a global.html file that retrieves the settings and will send a message back to my injection script as soon as I figure out how to go about doing that.
Since I'm doing all of my work before the document loads, all of the methods I've found to send message back rely on a page object that I don't have.
Like everyone else at this point, I'm still climbing the learning curve, but here's how I've handled this problem:
I have a simple extension with no chrome and one injected end script (script.js). For the purpose of loading settings I've added a simple global page (proxy.html). When script.js is injected, it sends a getSettings message to proxy.html. proxy.html responds with a setSettings message, and script.js continues initialization.
The most helpful page I've found in the docs on this topic is Messages and Proxies.
proxy.html:
<!doctype html>
<html lang="en">
<head>
<script type="text/javascript">
safari.application.addEventListener( "message", function( e ) {
if( e.name === "getSettings" ) {
e.target.page.dispatchMessage( "setSettings", {
sort_keys: safari.extension.settings.getItem( "sort_keys" )
} );
}
}, false );
</script>
</head>
<body></body>
</html>
script.js:
( function() {
var settings, init = function() {
// do extension stuff
};
// listen for an incoming setSettings message
safari.self.addEventListener( "message", function( e ) {
if( e.name === "setSettings" ) {
settings = e.message;
init();
}
}, false );
// ask proxy.html for settings
safari.self.tab.dispatchMessage( "getSettings" );
}() )
EDIT: like you said in your initial post update, the injected script doesn't have the same kind of access that a global HTML page would have. This is my working solution, imagine you want to know the value of setting "foo" in the injected script:
Injected script code:
function getMessage(msgEvent) {
if (msgEvent.name == "settingValueIs")
alert("Value for asked setting is: " + msgEvent.message);
}
safari.self.tab.dispatchMessage("getSettingValue", "foo"); // ask for value
safari.self.addEventListener("message", getMessage, false); // wait for reply
Global HTML code:
function respondToMessage(messageEvent) {
if (messageEvent.name == "getSettingValue") {
// getItem("foo");
var value = safari.extension.settings.getItem(messageEvent.message);
// return value of foo to injected script
safari.application.activeBrowserWindow.activeTab.page.dispatchMessage("settingValueIs", value);
}
}
safari.application.addEventListener("message",respondToMessage,false);
Hope this helps !
Initial post: I'm having the same 2nd problem as you, I can't access my settings (or secureSettings) from an injected script. In my case the script is loaded after page load, but even that way I can't use safari.extension.settings.
The only way it works is with a toolbar/button, the HTML behind that element can getItem and setItem as expected.
My conclusion is that, for some reason, injected scripts can't access settings (actually, they don't even seem to have access to the safari element). Bug or intended feature, that's left to figure out.
It took me several days, but I think I found a workable solution using the canLoad() messaging method. My injection script retrieves settings by calling the global HTML page like this:
settings = safari.self.tab.canLoad( event );
My global HTML file, in turn, returns those settings as:
settings = {
'setting1': safari.extension.settings.getItem( 'setting1' )
}
msgEvent.message = settings;
It's still a bit more "hacky" than I'd like. I can't seem to simply return the settings object itself, so I have to compile a new object by retrieving each setting manually. Not ideal, but it does seem to be effective.
run into the same problem, but the answer is easier than you can imagine: include the script in your global html.
<!DOCTYPE HTML>
<script type="text/javascript" src="cleanup.js"></script>
<script>
…
</script>
then you can access the settings as described in documentation safari.extension.settings.myKey
you can also upvote #Travis, because I got the idea from his post
//EDIT:
actually I don't really know whats wrong. Calling the settings as the first command works, but not at a later time. Additionally it seems to corrupting my complete script after the 2. injection. Need verification if it's only in my (difficult?) script.
//EDIT2:
now I got it to work to get back the settings object via dispatchMessage()
in your injected.js
function gotSettings(msgEvent) {
if (msgEvent.name === "SETTINGS") {
setts = msgEvent.message;
alert(setts.mySetting1);
// run the programm
}
}
safari.self.addEventListener("message", gotSettings, false);
safari.self.tab.dispatchMessage("getSettings");
and in global.html
switch (event.name) {
case "getSettings":
// send the settings data
event.target.page.dispatchMessage("SETTINGS", safari.extension.settings);
relying on this apple documentation