How do I add a language formatter which is a terminal command? - visual-studio-code

We have a language format command mint format src/main.mint which edits the file in place. Is there an appropriate way to register this action as a document formatter such that it can be fired when someone pressed Shift+Option+F?

You can copy the file to a temp directory, modify it with the command line tool, then read and provide it to VSCode
formatter.ts
import vscode = require("vscode");
import cp = require("child_process");
import fs = require("fs");
import { getDirtyFile } from "./utils";
export class MintFormattingProvider
implements vscode.DocumentFormattingEditProvider {
public provideDocumentFormattingEdits(
document: vscode.TextDocument,
options: vscode.FormattingOptions,
token: vscode.CancellationToken
): vscode.TextEdit[] | Thenable<vscode.TextEdit[]> {
return new Promise((resolve, reject) => {
let file = getDirtyFile(document);
let res = cp.spawnSync("mint", ["format", file], {
cwd: vscode.workspace.rootPath,
});
if (res.status !== 0) {
reject(res.error);
} else {
if (!fs.existsSync(file)) {
reject(file + " file not found");
} else {
let content = fs.readFileSync(file, "utf-8");
let range = document.validateRange(
new vscode.Range(
new vscode.Position(0, 0),
new vscode.Position(1000000, 1000000)
)
);
resolve([vscode.TextEdit.replace(range, content)]);
}
}
});
}
}
utils.ts
import fs = require("fs");
import path = require("path");
import os = require("os");
import vscode = require("vscode");
/**
* Returns temporary file path of edited document.
*/
export function getDirtyFile(document: vscode.TextDocument): string {
var dirtyFilePath = path.normalize(
path.join(os.tmpdir(), "vscodemintdirty.mint")
);
fs.writeFileSync(dirtyFilePath, document.getText());
return dirtyFilePath;
}
export function createAndShowOutputWindow(): vscode.OutputChannel {
var channel = vscode.window.createOutputChannel("mint");
channel.show();
return channel;
}

Related

How to get user's password?

How to get user password with Vala? Secret.prompt.perform_sync() seems doesn't work.
I really don't know how use secret.prompt.
Main.vala:
class SecretServ : Secret.Service {
}
class SecPrompt : Secret.Prompt {
}
class ApplicationWindow : Gtk.ApplicationWindow {
construct {
show_all();
var ret = new VariantType("s");
string winid;
winid = "%d".printf((int) this.get_id());
SecPrompt prompt = new SecPrompt();
try {
prompt.perform_sync(winid, null, ret);
} catch (GLib.Error e) {
stderr.printf("ERROR: %s", e.message);
}
}
}
class Application : Gtk.Application {
public Application() {
Object(
application_id: "com.github.urandom0.pass",
flags: ApplicationFlags.FLAGS_NONE
);
}
protected override void activate() {
ApplicationWindow window = new ApplicationWindow();
this.add_window(window);
}
}
static int main(string[] args) {
var app = new Application();
return app.run(args);
}
Compile:
valac Main.vala --pkg=gtk+-3.0 --pkg=libsecret-1
Run:
./Main
You can't just create a Secret.Prompt like that. It is an object that is created by the libsecret library internally.
There is a Vala example on how to use libsecret here:
https://developer-old.gnome.org/libsecret/0.18/vala-examples.html
I will summarize the example as an answer below.
You have to first create a schema:
var example = new Secret.Schema ("org.example.Password", Secret.SchemaFlags.NONE,
"number", Secret.SchemaAttributeType.INTEGER,
"string", Secret.SchemaAttributeType.STRING,
"even", Secret.SchemaAttributeType.BOOLEAN);
Then you can store properties into the schema:
var attributes = new GLib.HashTable<string,string> ();
attributes["number"] = "8";
attributes["string"] = "eight";
attributes["even"] = "true";
Secret.password_storev.begin (example_schema, attributes, Secret.COLLECTION_DEFAULT,
"The label", "the password", null, (obj, async_res) => {
bool res = Secret.password_store.end (async_res);
/* ... do something now that the password has been stored */
});
And finally retrieve them again:
var attributes = new GLib.HashTable<string,string> ();
attributes["number"] = "8";
attributes["string"] = "eight";
attributes["even"] = "true";
Secret.password_lookupv.begin (example_schema, attributes, null, (obj, async_res) => {
string password = Secret.password_lookup.end (async_res);
});
For more details read the whole libsecret documentation at:
https://developer-old.gnome.org/libsecret/0.18/index.html

How to get the File Extension from a string Path

I've got file path saved in variable and I want to get the file type extension by using path package https://pub.dev/packages/path So far I managed to do it by splitting the string like this
final path = "/some/path/to/file/file.dart";
print(path.split(".").last); //prints dart
Is there any way to achieve this with path package?
You can use the extension function in the path package to get the extension from a file path:
import 'package:path/path.dart' as p;
final path = '/some/path/to/file/file.dart';
final extension = p.extension(path); // '.dart'
If your file has multiple extensions, like file.dart.js, you can specify the optional level parameter:
final extension = p.extension('file.dart.js', 2); // '.dart.js'
No need of any extension. You can try below code snippet.
String getFileExtension(String fileName) {
try {
return "." + fileName.split('.').last;
} catch(e){
return null;
}
}
This small function can parse filepath or url and find basename, extension and absolute path. It doesn't check file path exist and not check basename is folder or file.
Map parsePath(String filepath) {
Map p1 = new Map();
int ind1 = filepath.indexOf("://");
if (ind1 > 0) {
p1["fullpath"] = filepath;
} else {
p1["fullpath"] = File(filepath).absolute.path;
}
p1["path"] = filepath;
List<String> v = filepath.split("/");
if (v.length > 1) {
p1["basename"] = v.last;
} else if (filepath.split("\\").length > 1) {
p1["basename"] = filepath.split("\\").last;
} else {
p1["basename"] = v.last;
}
p1["extension"] = p1["basename"].split('.').last;
if (p1["basename"] == p1["extension"]) p1["extension"] = "";
return p1;
}

VSCode Selection to snippet

It's a beginner question so don't be to hard to me.
Example:
A,B,C,D, ..
I need to convert this string to the following output in VSCode
enum id name
{
value(0; A) { Caption = 'A'; }
value(1; B) { Caption = 'B'; }
value(2; C) { Caption = 'C'; }
value(3; D) { Caption = 'D'; }
}
I can read the selection and split it into separate tokens.
But I'm stuck when it comes to writing it back to my line.
My Code:
'use strict';
// The module 'vscode' contains the VS Code extensibility API
// Import the module and reference it with the alias vscode in your code below
//import * as vscode from 'vscode';
import { window, commands, Disposable, ExtensionContext, StatusBarAlignment, StatusBarItem, TextDocument, TextEditor, ViewColumn, workspace, TextLine, TextEdit, Uri, Position } from 'vscode';
import { stringify } from 'querystring';
// this method is called when your extension is activated
// your extension is activated the very first time the command is executed
export function activate(context: ExtensionContext) {
console.log('"Cg Helper" is now active!');
let cgHelper = new CgALHelper;
let disp = commands.registerCommand('extension.convertSelection2Enum', () =>{
cgHelper.convertSelection2Enum(window.activeTextEditor);
})
context.subscriptions.push(disp);
}
// this method is called when your extension is deactivated
export function deactivate() {
}
class CgALHelper
{
public convertSelection2Enum(editor: TextEditor)
{
this.convertTextLine2Enum(editor);
}
public convertInputText2Enum()
{
}
private convertTextLine2Enum(editor: TextEditor)
{
let line = editor.document.lineAt(editor.selection.active.line);
if (line != null && line.text != null)
{
window.showInformationMessage(line.text);
let tokens = line.text.split(',');
if (tokens[0] != null && tokens[0] != '' && tokens.length != 0 )
{
tokens.forEach(tok => {
// I'm stuck here !
});
} else
window.showErrorMessage('nothing to convert');
} else
window.showErrorMessage('Nothing to convert');
}
}
You want to construct a SnippetString. Snippet strings can be constructed incrementally:
const snippet = new vscode.SnippetString();
snippet.appendText('enum id name {');
tokens.forEach(tok => {
snippet.appendText(` value(0; ${tok}) { Caption = '${tok}'; }`)
});
snippet.appendText('}');
Then apply the snippet to the editor using TextEditor.insertSnippet:
editor.insertSnippet(snippet);

Is there a way to use fs sync functions with browserify?

I already tried the brfs transformation, but I got the following error message:
08 03 2016 16:50:14.894:ERROR [framework.browserify]: bundle error
08 03 2016 16:50:14.894:ERROR [framework.browserify]: Error: tried to statically call { readFile: [Function: readFile], readFileSync: [Function: readFileSync], readdir: [Function: readdir], readdirSync: [Function: readdirSync] } as a function while parsing file
...
PhantomJS 1.9.8 (Windows 7 0.0.0) ERROR
You need to include some adapter that implements __karma__.start method!
when I try to use var fs = require("fs"); console.log(fs.readFileSync) in my code. Is there a way to use sync fs functions with browserify?
I want to process some non-js files which are served but no included by karma and not preprocessed by browserify. So what I need is glob and read. Any other idea how to process these files? The ideal solution would be to do it with nodejs, but I am not sure how to send the data from nodejs to the browser by using karma.
I did not manage to make the brfs work. I created a simple fs shim instead, which supports the following features:
existsSync(path) -> true/false
readdirSync(path) -> basename[]
statSync(path) -> {isDirectory}
readFileSync(path,"utf8") -> string
It uses path-browserify, so you need to replace the require("path") dependency if you use it in a non-browserify environment. Be aware that this fs shim uses window.__karma__.files, to build a directory and file tree, so it won't work without Karma. You can use the same logic if you are able to collect the file paths from browserify. I guess you need to write a browserify plugin for that.
module.exports = (function () {
var path = require("path");
function absolutePath(relativePath) {
return path.resolve(path.normalize(relativePath.split("\\").join("/")));
}
var KarmaFileSystem = function () {
this.registry = new KarmaPathRegistry();
this.converter = new KarmaUriPathConverter("/base/", "/");
this.reader = new KarmaFileReader(this.converter);
var servedUris = Object.keys(window.__karma__.files);
var servedFiles = this.converter.parseUris(servedUris);
servedFiles.forEach(this.registry.addFile, this.registry);
};
KarmaFileSystem.prototype = {
constructor: KarmaFileSystem,
workingDirectory: "/",
existsSync: function (path) {
return this.registry.exists(path);
},
readdirSync: function (path) {
return this.registry.getContent(path);
},
statSync: function (path) {
return {
isDirectory: function () {
return this.registry.isDirectory(path);
}.bind(this)
};
},
readFileSync: function (file, encoding) {
if (encoding !== "utf8")
throw new Error("This fs.readFileSync() shim does not support other than utf8 encoding.");
if (!this.registry.isFile(file))
throw new Error("File does not exist: " + file);
return this.reader.readFile(file);
}
};
var KarmaPathRegistry = function KarmaPathRegistry() {
this.paths = {};
};
KarmaPathRegistry.prototype = {
constructor: KarmaPathRegistry,
addFile: function (file) {
file = absolutePath(file);
this.paths[file] = KarmaPathRegistry.TYPE_FILE;
var parentDirectory = path.dirname(file);
this.addDirectory(parentDirectory);
},
addDirectory: function (directory) {
directory = absolutePath(directory);
this.paths[directory] = KarmaPathRegistry.TYPE_DIRECTORY;
var parentDirectory = path.dirname(directory);
if (parentDirectory != directory)
this.addDirectory(parentDirectory);
},
isFile: function (file) {
file = absolutePath(file);
return this.exists(file) && this.paths[file] === KarmaPathRegistry.TYPE_FILE;
},
isDirectory: function (directory) {
directory = absolutePath(directory);
return this.exists(directory) && this.paths[directory] === KarmaPathRegistry.TYPE_DIRECTORY;
},
exists: function (node) {
node = absolutePath(node);
return this.paths.hasOwnProperty(node);
},
getContent: function (directory) {
if (!this.isDirectory(directory))
throw new Error("Not a directory: " + directory);
directory = absolutePath(directory);
return Object.keys(this.paths).filter(function (node) {
if (node === directory)
return false;
var parentDirectory = path.dirname(node);
return parentDirectory === directory;
}, this).map(function (node) {
return path.basename(node);
});
}
};
KarmaPathRegistry.TYPE_FILE = 0;
KarmaPathRegistry.TYPE_DIRECTORY = 1;
var KarmaUriPathConverter = function KarmaUriPathConverter(baseUri, workingDirectory) {
this.workingDirectory = workingDirectory;
this.workingDirectoryPattern = this.patternFromBase(workingDirectory);
this.baseUri = baseUri;
this.baseUriPattern = this.patternFromBase(baseUri);
};
KarmaUriPathConverter.prototype = {
constructor: KarmaUriPathConverter,
patternFromBase: function (string, flags) {
var pattern = "^" + string.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&');
return new RegExp(pattern, flags);
},
parseUris: function (uris) {
return uris.filter(function (uri) {
return this.baseUriPattern.test(uri)
}, this).map(function (uri) {
return uri.replace(this.baseUriPattern, this.workingDirectory);
}, this);
},
buildUri: function (file) {
file = absolutePath(file);
if (!this.workingDirectoryPattern.test(file))
throw new Error("Path is not in working directory: " + file);
return file.replace(this.workingDirectoryPattern, this.baseUri);
}
};
var KarmaFileReader = function KarmaFileReader(converter) {
this.converter = converter;
};
KarmaFileReader.prototype = {
constructor: KarmaFileReader,
readFile: function (file) {
var uri = this.converter.buildUri(file);
var xhr = new XMLHttpRequest();
xhr.open("get", uri, false);
xhr.send();
return xhr.responseText;
}
};
return new KarmaFileSystem();
})();

multiple file upload using html5 drag-and-drop fails as multiple files get same content

I need to transfer all the files dropped on an element to a server using HTML5 drag and drop.
I provided the corresponding js code below. I have a servlet in the server side to collect the files and put it in a folder. This is working fine if I drop 1 or 2 files on the page. But, if i drop 4-10 files, all the files are getting created in the server but multiple files are set to same content and some files content is 0K.
Can any of you please tell me how to achieve the correct behavior.
My requirement is similar to gmail attachments!!
Any solution which makes a sequential upload of files is much appreciable.
/*
* Upload files to the server using HTML 5 Drag and drop from the folders on your local computer
*/
function uploader(place, status, target, show) {
// Upload image files
upload = function(file) {
// Firefox 3.6, Chrome 6, WebKit
if(window.FileReader) {
// Once the process of reading file
this.loadEnd = function() {
bin = reader.result;
xhr = new XMLHttpRequest();
xhr.open('POST', target+'?up=true', false);
var body = bin;
xhr.setRequestHeader('content-type', 'multipart/form-data;');
xhr.setRequestHeader("file-name", file.name );
xhr.setRequestHeader("mime-type", file.type );
// Firefox 3.6 provides a feature sendAsBinary ()
if(xhr.sendAsBinary != null) {
xhr.sendAsBinary(body);
// Chrome 7 sends data but you must use the base64_decode on the PHP side
} else {
xhr.open('POST', target+'?up=true&base64=true', true);
xhr.setRequestHeader('UP-FILENAME', file.name);
xhr.setRequestHeader('UP-SIZE', file.size);
xhr.setRequestHeader('UP-TYPE', file.type);
xhr.send(window.btoa(bin));
}
if (show) {
var newFile = document.createElement('div');
newFile.innerHTML = 'Loaded : '+file.name+' size '+file.size+' B';
document.getElementById(show).appendChild(newFile);
}
if (status) {
document.getElementById(status).innerHTML = 'Loaded : 100%<br/>Next file ...';
}
};
// Loading errors
this.loadError = function(event) {
switch(event.target.error.code) {
case event.target.error.NOT_FOUND_ERR:
document.getElementById(status).innerHTML = 'File not found!';
break;
case event.target.error.NOT_READABLE_ERR:
document.getElementById(status).innerHTML = 'File not readable!';
break;
case event.target.error.ABORT_ERR:
break;
default:
document.getElementById(status).innerHTML = 'Read error.';
}
};
// Reading Progress
this.loadProgress = function(event) {
if (event.lengthComputable) {
var percentage = Math.round((event.loaded * 100) / event.total);
document.getElementById(status).innerHTML = 'Loaded : '+percentage+'%';
}
};
// Preview images
this.previewNow = function(event) {
bin = preview.result;
var img = document.createElement("img");
img.className = 'addedIMG';
img.file = file;
img.src = bin;
document.getElementById(show).appendChild(img);
};
reader = new FileReader();
// Firefox 3.6, WebKit
if(reader.addEventListener) {
reader.addEventListener('loadend', this.loadEnd, false);
if (status != null)
{
reader.addEventListener('error', this.loadError, false);
reader.addEventListener('progress', this.loadProgress, false);
}
// Chrome 7
} else {
reader.onloadend = this.loadEnd;
if (status != null)
{
reader.onerror = this.loadError;
reader.onprogress = this.loadProgress;
}
}
var preview = new FileReader();
// Firefox 3.6, WebKit
if(preview.addEventListener) {
preview.addEventListener('loadend', this.previewNow, false);
// Chrome 7
} else {
preview.onloadend = this.previewNow;
}
// The function that starts reading the file as a binary string
reader.readAsBinaryString(file);
// Preview uploaded files
if (show) {
preview.readAsDataURL(file);
}
// Safari 5 does not support FileReader
} else {
xhr = new XMLHttpRequest();
xhr.open('POST', target+'?up=true', true);
xhr.setRequestHeader('UP-FILENAME', file.name);
xhr.setRequestHeader('UP-SIZE', file.size);
xhr.setRequestHeader('UP-TYPE', file.type);
xhr.send(file);
if (status) {
document.getElementById(status).innerHTML = 'Loaded : 100%';
}
if (show) {
var newFile = document.createElement('div');
newFile.innerHTML = 'Loaded : '+file.name+' size '+file.size+' B';
document.getElementById(show).appendChild(newFile);
}
}
};
// Function drop file
this.drop = function(event) {
event.preventDefault();
var dt = event.dataTransfer;
var files = dt.files;
for (var i = 0; i<files.length; i++) {
var file = files[i];
upload(file);
}
};
// The inclusion of the event listeners (DragOver and drop)
this.uploadPlace = document.getElementById(place);
this.uploadPlace.addEventListener("dragover", function(event) {
event.stopPropagation();
event.preventDefault();
}, true);
this.uploadPlace.addEventListener("drop", this.drop, false);
}
Thank you.
I spent sometimes this morning in analyzing the same code from html5uploader. With some lucks, I found the root cause.
Change reader = new FileReader(); to var reader = new FileReader(); should solve the issue.
I bet this is because javascripts behaviour of auto-declaring undeclared variable as global variable. This caused the reader variable being reused by all the uploade(file) calls when more than one file is dropped to the browser.
Cheers!