How do I write vim-latex like custom key bindings into the Overleaf (Codemirror) editor? - vim

I am aware that Tampermonkey (https://www.tampermonkey.net/) could potentially do this. I installed a Tampermonkey chrome extension, and under "Dashboard", I added the following userscript (All the commented-out lines I tried below << CodeMirrorVim.Vim.map("jj", "", "insert");>> didn't work).
// ==UserScript==
// #name Overleaf Editor Custom VIM Keybindings
// #namespace http://tampermonkey.net/
// #version 0.1
// #match https://www.overleaf.com/project/*
// #grant none
// ==/UserScript==
(function() {
'use strict';
window.addEventListener("UNSTABLE_editor:extensions", (event) => {
const { CodeMirror, CodeMirrorVim, extensions } = event.detail;
// add custom keybindings - insert mode applies on insert
CodeMirrorVim.Vim.map("jj", "<Esc>", "insert");
// CodeMirrorVim.Vim.map("kk", "Right-Right", "insert");
// CodeMirrorVim.Vim.map("ECI", "\\cite{<++>}<++>", "insert");
// CodeMirrorVim.Vim.map("aa", "<Down>", "insert");
// CodeMirrorVim.Vim.imap("`a", "\alpha", "insert");
// CodeMirrorVim.IMAP('FMB', "\\mathbb{<++>}<++>", 'insert')
// normal mode applies while escaped
// CodeMirrorVim.Vim.map("h", "j", "normal");
// CodeMirrorVim.Vim.map("hh", "<Right>", "normal");
});
})();
CodeMirrorVim.Vim.map("jj", "<Esc>", "insert");
works but
CodeMirrorVim.Vim.map("kk", "<Right>", "insert");
CodeMirrorVim.Vim.map("kk", "Right-Right", "insert");
CodeMirrorVim.Vim.map("kk", "<Esc>-<Right>", "insert");
all didn't work. So how do I write, for example, the following bindings in 'tex.vim" in Tampermonkey userscript?
Here is keybindings in my "tex.vim":
call IMAP ('FTX', "\\text{<++>}<++>", 'tex')
call IMAP ('FCA', "\\mathcal{<++>}<++>", 'tex')
call IMAP ('EBM', "\\begin{bmatrix}\<CR><++>\<CR>\\end{bmatrix}", 'tex')
imap kk <C-j>
Also it would be nice if we could input greeks in overleaf CodeMirror editor as we do using vim-latex:
typing "`a" gives "\alpha".

Related

How to disable Chrome's session restore warning using nodejs?

How to reboot the Chromium/Google Chrome (kiosk mode) in Windows via NodeJS so that it normally on restart starts the browser as it was used by a normal human? (when i use nodeJS every single time on restart of Chromium/Google chrome keep showing me that ugly/annoying/deadly popup on right top corner)
NodeJS: tell chrome to switch off
NodeJS: tell chrome to start now: on every single start it keeps opening that ugly popup on the right top corner and there is no way to remove that without human involved
var wait_seconds = null;
function reboot_chrome() {
// taskkill /f /im chrome.exe
run_cmd( "taskkill", ["/f", "/im", "chrome.exe"], function(text) {
console.log (text);
});
//$ cat C:/Python27/run.bat:
//#echo off
//#start /b cmd /c "C:\Users\tpt\AppData\Local\Chromium\Application\chrome.exe" --kiosk
wait_seconds = setTimeout(function() {
run_cmd("C:\\Python27\\run.bat", [], function(text){
console.log(text);
});
}, 20000);
}
You could use the --incognito or --disable-session-crashed-bubble --disable-infobars switches, but the browser wouldn't behave completely as expected.
The cleanest way would be to change the exit_type in the preferences of the user profile. Here's a small example doing exactly that:
var fs = require("fs");
var path = require("path");
var exec = require("child_process").exec;
//----------------------------------------------------
function restartChrome(){
stopChrome();
setTimeout(startChrome, 20000);
}
//----------------------------------------------------
function startChrome(){
// change this path to your application path
exec('"C:\\Program Files (x86)\\Google\\Chrome\\Application\\chrome" --kiosk')
}
//----------------------------------------------------
function stopChrome(){
exec("taskkill /IM chrome.exe /f");
setExitType();
}
//----------------------------------------------------
function setExitType(callback){
// change this path to your session preferences path
var preferencesPath = path.join(process.env["USERPROFILE"], "AppData/Local/Google/Chrome/User Data/Default/Preferences");
fs.readFile(preferencesPath, "utf8", function(err, data){
if (err) { return callback && callback(err); }
var txt = data.replace(/exit_type":"Crashed/g, 'exit_type":"None')
.replace(/exited_cleanly":false/g, 'exited_cleanly":true');
fs.writeFile(preferencesPath, txt, "utf8", callback);
});
}
restartChrome();
Remember to adjust the paths for the application and preferences file as marked in the comments.

Greasemonkey: click a link

I would like to click on this link using Greasemonkey:
<a class="bbbx-button bbbx-button-grey" id="vote-button" data-bbbx-trigger="module.vote.submit" data-bbbx-id="51526" data-bbbx-score="10" data-bbbx-vote-type="up"><img src="//du3rc6beq6sv9.cloudfront.net/release1406643004647-5-1-2-1/assets/skins/default/images/vote/heart.png"> vote! <small id="vote-count">( 14 )</small></a>
I tried this code:
// ==UserScript==
// #name test
// #namespace test
// #include *
// #version 1
// #require http://ajax.googleapis.com/ajax/libs/jquery/1.8.3/jquery.min.js
// #grant GM_addStyle
// ==/UserScript==
console.log("Start");
window.setTimeout(start, 7000);
function start()
{
$("a#vote-button")[0].click();
console.log("End clicktime");
}
But unfortunately I can't find the problem.
You don't have jQuery loaded in your GM script.
Add this:
// #require http://ajax.googleapis.com/ajax/libs/jquery/1.8.3/jquery.min.js
Feel free to change the version.
Have a look at this question, it also provides some solutions for websites that already have jQuery loaded: How can I use jQuery in Greasemonkey?

Create a "config" or "options" page for a Greasemonkey script

I've written a simple Greasemonkey script, and I'm trying to create a "config" page for this script (like the one that is used for Google Chrome extensions. ) Would there be any way to create a config page for a userscript, like the "options" pages for Google Chrome extensions? There isn't any way to include an .html page as part of a Greasemonkey script (as far as I know), so I'm looking for other options.
// ==UserScript==
// #name Redirector
// #namespace http://use.i.E.your.homepage/
// #version 0.1
// #description enter something useful
// #match http://*/*
// #copyright 2012+, You
// #run-at document-start
// ==/UserScript==
redirectToPage("http://www.youtube.com/", "http://www.google.com");
function redirectToPage(page1, page2){
if(window.location.href.indexOf(page1) != -1){
window.location.href = page2;
}
}
There are a few libraries which provide config pages for userscripts:
1) GM_config
2) MonkeyConfig
3) GM_registerMenuCommand Submenu JS Module
The usage varies per library, but typically you grant the permissions they need such as GM_getValue and GM_setValue, and require the library via the #require directive, e.g.:
// ==UserScript==
// #name My Userscript
// #description An example userscript with a config page
// #version 0.0.1
// #require https://www.example.com/lib/myconfig.js
// #grant GM_getValue
// #grant GM_setValue
// #grant GM_addStyle
// #grant GM_registerMenuCommand
// ==/UserScript==
const config = new MyConfig({ ... })
You then register a menu command which opens the config page/dialog, e.g.:
GM_registerMenuCommand('Configure My Userscript!', () => {
config.open()
})
In the case of MonkeyConfig, it can register the command for you:
const config = new MonkeyConfig({
title: 'Configure My Userscript!',
menuCommand: true,
// ...
})
For advanced uses, the configurator may allow listeners to be registered for the close/cancel/save events, as well as providing control over the CSS, and other options. Detailed instructions can be found on the GM_config wiki and the MonkeyConfig homepage.
If you are using it for chrome, then it isn't Greasemonkey but Tampermonkey.
You may consider using GM_getResourceText, paste your html to pastebin.com (or similar) and add the link as one of #resource to the metadata block.
At least, I know it works to Greasemonkey.
For example:
// #resource configHtml http://pastebin.com/raw.php?i=2RjKfwJQ
// ... some DOM node that you will append to the current page
node.innerHTML = GM_getResourceText("configHtml");
This is much needed but for now combination of 2 approaches should work.
1) For personal use I just have a bunch of variables at the top of the script. The problem here is that if anyone else uses my script an update ends up erasing his preferences.
2) Have a configuration page on your website. While this works wonderfully websites get deleted all the time. There is no good reason for a script to depend on a website to work.
If you do both those things the user can edit the preferences in the script when the scripts website vanishes.
Here is an example where undesired functionality is // commented out.
http://go-here.nl/gm/wikipedia-clean-up.php
Good luck and enjoy
Use a parameter to the page you're already including, and if that's set then clear the whole document:
http://page.my.script.runs.on/?configPage=true
if(getUrlParameter("configPage") === "true") {
$(document).empty
}
this userscript don't use any external libs. with modification you can make good UI.
// ==UserScript==
// #name UI development
// #namespace http://tampermonkey.net/
// #version 0.1
// #description try to take over the world!
// #author ManojBhakarPCM
// #match https://www.google.com/
// #grant none
// ==/UserScript==
(function() {
'use strict';
function ui_create(contentss){
var div = document.createElement('div');
//var contentss = "<h1>TESTsssss</h1>";
div.innerHTML = '<div id="mbpcm_modal" style="position: fixed;z-index: 1;left: 0;top: 0;width: 100%;height: 100%;overflow: auto;display:none;"><div id="mbpcm_content" style="background-color: pink;margin: 15% auto;padding: 20px;border: 1px solid black;width: 20%;box-shadow:20px 20px 30px 2px gray;border-radius:7px;"><span id="mbpcm_close" style="float: right;font-size:25px;cursor: pointer;">×</span>'+ contentss +'</div></div>';
document.body.appendChild(div);
var modal = document.getElementById("mbpcm_modal");
var close = document.getElementById("mbpcm_close");
close.onclick = function(){modal.style.display = "none";}
}
function ui_add_opener(parent,classs,stylee){
var btn = document.createElement("button");
btn.setAttribute("class",classs);
btn.setAttribute("style",stylee);
btn.setAttribute("id","mbpcm_ui_opener");
btn.innerHTML = "Settings";
parent.appendChild(btn);
var modal = document.getElementById("mbpcm_modal");
var btnn = document.getElementById("mbpcm_ui_opener");
btnn.onclick = function(){modal.style.display = "block";}
}
function ui_addElement(el,cls,styl,val,innerHtml){
var modal = document.getElementById("mbpcm_content");
var e = document.createElement(el);
e.setAttribute("class",cls);
e.setAttribute("style",styl);
e.setAttribute("value",val);
e.innerHTML = innerHtml;
modal.appendChild(e);
return e;
}
ui_create("<h1>Title</h1><span>discription</span><br>");
ui_add_opener(document.getElementById("gbw"),"RNmpXc","nothing");
ui_addElement("button","modal","none","none","TestButton").onclick = function(){alert("hellow ji ");}
ui_addElement("br","","","","");
ui_addElement("button","none","none","none","TestButton").onclick = function(){alert("How are you");}
ui_addElement("button","none","none","none","TestButton").onclick = function(){alert("Kaise ho");}
})();

Gnome Shell Extension Key Binding

What is the simplest way to (globally) bind a key combination (e.g. <Super>+A) to a function in a gnome shell extension?
Inspecting a couple of extensions, I ran into the following code:
global.display.add_keybinding('random-name',
new Gio.Settings({schema: 'org.gnome.shell.keybindings'}),
Meta.KeyBindingFlags.NONE,
function() { /* ... some code */ });
I understand that the key combination is specified by the schema parameter, and that it's possible to create an XML file describing the combination. Is there a simpler way to do this?
The question is old, but I just implemented that for Gnome Shell 40. So here is how I did it.
The key is defined in your normal schema file that you use for the settings of the extension. So it looks like this:
<?xml version="1.0" encoding="UTF-8"?>
<schemalist>
<schema id="org.gnome.shell.extensions.mycoolstuff" path="/org/gnome/shell/extensions/mycoolstuff/">
<key name="cool-hotkey" type="as">
<default><![CDATA[['<Ctrl><Super>T']]]></default>
<summary>Hotkey to open the cool stuff.</summary>
</key>
... other config options
</schema>
</schemalist>
The key type is a "Array of String", so you can configure multiple key-combinations for the action.
In your code you use it like this:
const Main = imports.ui.main;
const Meta = imports.gi.Meta
const Shell = imports.gi.Shell
const ExtensionUtils = imports.misc.extensionUtils;
...
let my_settings = ExtensionUtils.getSettings("org.gnome.shell.extensions.mycoolstuff");
Main.wm.addKeybinding("cool-hotkey", my_settings,
Meta.KeyBindingFlags.IGNORE_AUTOREPEAT,
Shell.ActionMode.NORMAL | Shell.ActionMode.OVERVIEW
this._hotkeyActionMethod.bind(this));
I would recommend to remove the key binding when the extension gets disabled.
Don't know what happens if you don't do this.
Main.wm.removeKeybinding("cool-hotkey");
BTW: Changes to the settings (via dconf editor, gsettings or your extensions preferences) are active immediately.
Following is a copy of my answer here
I've only tested this in Gnome 3.22
TL;DR
Here is a class:
KeyManager: new Lang.Class({
Name: 'MyKeyManager',
_init: function() {
this.grabbers = new Map()
global.display.connect(
'accelerator-activated',
Lang.bind(this, function(display, action, deviceId, timestamp){
log('Accelerator Activated: [display={}, action={}, deviceId={}, timestamp={}]',
display, action, deviceId, timestamp)
this._onAccelerator(action)
}))
},
listenFor: function(accelerator, callback){
log('Trying to listen for hot key [accelerator={}]', accelerator)
let action = global.display.grab_accelerator(accelerator)
if(action == Meta.KeyBindingAction.NONE) {
log('Unable to grab accelerator [binding={}]', accelerator)
} else {
log('Grabbed accelerator [action={}]', action)
let name = Meta.external_binding_name_for_action(action)
log('Received binding name for action [name={}, action={}]',
name, action)
log('Requesting WM to allow binding [name={}]', name)
Main.wm.allowKeybinding(name, Shell.ActionMode.ALL)
this.grabbers.set(action, {
name: name,
accelerator: accelerator,
callback: callback
})
}
},
_onAccelerator: function(action) {
let grabber = this.grabbers.get(action)
if(grabber) {
this.grabbers.get(action).callback()
} else {
log('No listeners [action={}]', action)
}
}
})
And that's how you you use it:
let keyManager = new KeyManager()
keyManager.listenFor("<ctrl><shift>a", function(){
log("Hot keys are working!!!")
})
You're going to need imports:
const Lang = imports.lang
const Meta = imports.gi.Meta
const Shell = imports.gi.Shell
const Main = imports.ui.main
Explanation
I might be terribly wrong, but that what I've figured out in last couple days.
First of all it is Mutter who is responsible for listening for hotkeys. Mutter is a framework for creating Window Managers, it is not an window manager itself.
Gnome Shell has a class written in JS and called "Window Manager" - this is the real Window Manager which uses Mutter internally to do all low-level stuff.
Mutter has an object MetaDisplay. This is object you use to request listening for a hotkey.
But!
But Mutter will require Window Manager to approve usage of this hotkey. So what happens when hotkey is pressed?
- MetaDisplay generates event 'filter-keybinding'.
- Window Manager in Gnome Shell checks if this hotkey allowed to be processed.
- Window Manager returns appropriate value to MetaDisplay
- If it is allowed to process this hotkey, MetaDisplay generates event 'accelerator-actived'
- Your extension must listen for that event and figure out by action id which hotkey is activated.
Same as that of #p2t2p but recast using ES5 class. This is also using my logger class but you can replace that with log().
const Lang = imports.lang
const Meta = imports.gi.Meta
const Shell = imports.gi.Shell
const Main = imports.ui.main
const ExtensionUtils = imports.misc.extensionUtils;
const Me = ExtensionUtils.getCurrentExtension();
const Logger = Me.imports.logger.Logger;
var KeyboardShortcuts = class KeyboardShortcuts {
constructor(settings) {
this._grabbers = {};
this.logger = new Logger('kt kbshortcuts', settings);
global.display.connect('accelerator-activated', (display, action, deviceId, timestamp) => {
this.logger.debug("Accelerator Activated: [display=%s, action=%s, deviceId=%s, timestamp=%s]",
display, action, deviceId, timestamp)
this._onAccelerator(action)
});
}
listenFor(accelerator, callback) {
this.logger.debug('Trying to listen for hot key [accelerator=%s]', accelerator);
let action = global.display.grab_accelerator(accelerator, 0);
if (action == Meta.KeyBindingAction.NONE) {
this.logger.error('Unable to grab accelerator [%s]', accelerator);
return;
}
this.logger.debug('Grabbed accelerator [action={}]', action);
let name = Meta.external_binding_name_for_action(action);
this.logger.debug('Received binding name for action [name=%s, action=%s]',
name, action)
this.logger.debug('Requesting WM to allow binding [name=%s]', name)
Main.wm.allowKeybinding(name, Shell.ActionMode.ALL)
this._grabbers[action]={
name: name,
accelerator: accelerator,
callback: callback
};
}
_onAccelerator(action) {
let grabber = this._grabbers[action];
if (grabber) {
grabber.callback();
} else {
this.logger.debug('No listeners [action=%s]', action);
}
}
}
and use it like,
this.accel = new KeyboardShortcuts(this.settings);
this.accel.listenFor("<ctrl><super>T", () => {
this.logger.debug("Toggling show endtime");
this._timers.settings.show_endtime = !this._timers.settings.show_endtime;
});

Clear terminal window in Node.js readline shell

I have a simple readline shell written in Coffeescript:
rl = require 'readline'
cli = rl.createInterface process.stdin, process.stdout, null
cli.setPrompt "hello> "
cli.on 'line', (line) ->
console.log line
cli.prompt()
cli.prompt()
Running this displays a prompt:
$ coffee cli.coffee
hello>
I would like to be able to hit Ctrl-L to clear the screen. Is this possible?
I have also noticed that I cannot hit Ctrl-L in either the node or coffee REPLs either.
I am running on Ubuntu 11.04.
You can watch for the keypress yourself and clear the screen.
process.stdin.on 'keypress', (s, key) ->
if key.ctrl && key.name == 'l'
process.stdout.write '\u001B[2J\u001B[0;0f'
Clearing is done with ASCII control sequences like those written here:
http://ascii-table.com/ansi-escape-sequences-vt-100.php
The first code \u001B[2J instructs the terminal to clear itself, and the second one \u001B[0;0f forces the cursor back to position 0,0.
Note
The keypress event is no longer part of the standard Node API in Node >= 0.10.x but you can use the keypress module instead.
In the MAC terminal, to clear the console in NodeJS, you just hit COMMAND+K just like in Google Developer Tools Console so I'm guessing that on Windows it would be CTRL+K.
This is the only answer that will clear the screen AND scroll history.
function clear() {
// 1. Print empty lines until the screen is blank.
process.stdout.write('\033[2J');
// 2. Clear the scrollback.
process.stdout.write('\u001b[H\u001b[2J\u001b[3J');
}
// Try this example to see it in action!
(function loop() {
let i = -40; // Print 40 lines extra.
(function printLine() {
console.log('line ' + (i + 41));
if (++i < process.stdout.columns) {
setTimeout(printLine, 40);
}
else {
clear();
setTimeout(loop, 3000);
}
})()
})()
The first line ensures the visible lines are always cleared.
The second line ensures the scroll history is cleared.
Try also:
var rl = require('readline');
rl.cursorTo(process.stdout, 0, 0);
rl.clearScreenDown(process.stdout);
On response to #loganfsmyth comment on his answer (thanks for the edit!).
I have been looking here and there and, besides of the wonderfull keypress module, there is a core module that makes possible to create a cli with all standard terminal behavior (all things we give for granted today such as history, options to provide an auto-complete function and input events such as keypress are there).
The module is readline (documentation). The good news is that all the standar behaviour is already done for us so there is no need to attach event handlers (i.e. history, clearing the screen on Ctrl+L, man if you provided the auto complete function it'll be on Tabpress).
Just as an example
var readline = require('readline')
, cli = readline.createInterface({
input : process.stdin,
output : process.stdout
});
var myPrompt = ' > myPropmt '
cli.setPrompt(myPrompt, myPrompt.length);
// prompt length so you can use "color" in your prompt
cli.prompt();
// Display ' > myPrompt ' with all standard features (history also!)
cli.on('line', function(cmd){ // fired each time the input has a new line
cli.prompt();
})
cli.input.on('keypress', function(key){ // self explanatory
// arguments is a "key" object
// with really nice properties such as ctrl : false
process.stdout.write(JSON.stringify(arguments))
});
Really good discovery.
The node version I'm using is v0.10.29. I have been looking at the changelog and it was there since 2010 (commit 10d8ad).
You can clear screen using console.log() and escape sequences.
cli.on 'line', (line) ->
if line == 'cls'
console.log("\033[2J\033[0f")
else
console.log line
cli.prompt()
Vorpal.js makes things like this really easy.
For an interactive CLI with a clear command as well as a REPL within the context of your application, do this:
var vorpal = require('vorpal')();
var repl = require('vorpal-repl');
vorpal
.delimiter('hello>')
.use(repl)
.show();
vorpal
.command('clear', 'Clears the screen.')
.action(function (args, cb) {
var blank = '';
for (var i = 0; i < process.stdout.rows; ++i) {
blank += '\n';
}
vorpal.ui.rewrite(blank);
vorpal.ui.rewrite('');
cb();
});
If you are using readline.createInterface you could do something like:
function clearPrompt() {
rl.setPrompt("");
rl.prompt();
}
Note this won't clear the entire terminal, just the readline prompt. Still useful if you want the user to keep their place in the terminal

Resources