VS Code API: How do I retrieve ExtensionContext outside of extension.ts? - visual-studio-code

I'm using VS Code API's ExtensionContext.globalState() to count the number of the times the sidebar of our extension has been opened. This is inside a command a handler in extension.ts and it counts the number of opens on local storage as expected.
I want to retrieve that count on a .js file where we are using JQuery to append components to the UI of the sidebar. However, I don't know how to retrieve ExtensionContext.globalState outisde of extension.ts
This is how I'm getting and updating the value of the count on extension.ts
const retrievedOpeningCountValue = context.globalState.get<Number>("sidebarOpeningCount");
// If show hasn't been called yet, retrieve 0, then increase it to 1 to store such value
let retrievedValue = retrievedOpeningCountValue?.valueOf() || 0;
let increasedValue = retrievedValue + 1;
context.globalState.update("sidebarOpeningCount", increasedValue);
And then I need to retrieve that number on my JQuery file. I can't do import * as vscode from "vscode"; because it't not a TS file. Even if it was, context: vscode.ExtensionContext can only be passed as a parameter to the activate function on extension.ts.
But basically I wanna do something like const retrievedOpeningCountValue = context.globalState.get<Number>("sidebarOpeningCount");on a js file. How do I do that?

You could simply assign context to some global / shared resource, and import it on any other .js/.ts file.
Something like:
extension.ts
export async function activate(context: vscode.ExtensionContext) {
Container.context = context;
container.ts
import { ExtensionContext } from "vscode";
export class Container {
private static _extContext: ExtensionContext;
public static get context(): ExtensionContext {
return this._extContext;
}
public static set context(ec: ExtensionContext) {
this._extContext = ec;
}
}
yourotherfile.ts
import { Container } from "../container";
...
const retrievedOpeningCountValue = Container.context.globalState.get<Number>("sidebarOpeningCount");

Related

How to see the value of a top level empty getter without running the code in Swift?

public var O_RDONLY: Int32 { get }
When I'm looking at stuff inside Darwin.sys.* or Darwin.POSIX.* for example, a lot of these constants are defined as getters. But how does one see the actual value without evaluating the code?
public var O_RDONLY: Int32 { get }
is what the Swift importer generates from the macro definition
#define O_RDONLY 0x0000 /* open for reading only */
in the <sys/fcntl.h> include file. Although this is a fixed value, known at compile time, the Swift importer does not show the value in the generated Swift interface.
Note also that a macro definition in a C header file may depend on other macros, and on other “variables” such as compiler flags, the processor architecture, etc.
I am not aware of a way to navigate to that C definition from a Swift file, or any other way to show the defined value in a pure Swift project. As a workaround, one can
add a C file to the project,
use the macro in some C function, and
“jump to definition” from there.
I ended up with the following solution:
const fs = require('fs');
const { exec } = require("child_process");
const getterRegEx = /^(.*)public var (.+): (.+) { get }(.*)$/;
const code = String(fs.readFileSync('./generatedSwift.swift'));
const lines = code.split('\n').map((line, i) => {
const arr = getterRegEx.exec(line);
if (arr) {
const [all, prefix, constant, type, suffix] = arr;
return `print("let ${constant}: ${type} = ", ${constant}, separator: "")`;
}
return `print("""\n${line}\n""")`;
});
lines.unshift('import Foundation');
fs.writeFileSync('./regeneratedSwift.swift', lines.join('\n'));
exec('swift ./regeneratedSwift.swift', (err, stdout, stderr) => {
if (err) {
console.error(`exec error: ${err}`);
return;
}
if (stderr) {
console.log(`stderr: ${stderr}`);
return;
}
console.log(`stdout: ${stdout}`);
});
Copy definitions generated by the XCode and save into a file named generatedSwift.swift the run node index.js in the same folder.
The output will contain the Swift code where all
public var Constant: Type { get }
are replaced with
let Constant = Value
and all other lines will remain the same.

Wagtail - how to get tags to work with `telepath` (tags in streamfield)?

I can use tags in regular page fields without any issue. When using tags within blocks (within a streamfield), the UI works and the tags are saved BUT the current page tags do not show up when loading the page in the admin. That's because the current value is not in the template anymore, it's in a JSON loaded via telepath.
I can confirm that the tags are saved and present in the data passed to initBlockWidget in the page source but these are ignored. Also, if I used a regular text field instead of the tag-widget, I can see the saved-values in the admin.
This is the code I have (which used to be enough before the refactor with telepath).
from wagtail.admin.widgets import AdminTagWidget
class TagBlock(TextBlock):
#cached_property
def field(self):
field_kwargs = {"widget": AdminTagWidget()}
field_kwargs.update(self.field_options)
return forms.CharField(**field_kwargs)
I think the following link is what I need to complete somehow to get it to work: https://docs.wagtail.io/en/stable/reference/streamfield/widget_api.html#form-widget-client-side-api
I've tried with this:
class AdminTagWidgetAdapter(WidgetAdapter):
class Media:
js = [
"wagtailadmin/js/vendor/tag-it.js",
"js/admin/admin-tag-widget-adapter.js",
]
register(AdminTagWidgetAdapter(), AdminTagWidget)
And under js/admin/admin-tag-widget-adapter.js:
console.log("adapter"); // this shows up in the console
class BoundWidget { // copied from wagtail source code
constructor(element, name, idForLabel, initialState) {
var selector = ':input[name="' + name + '"]';
this.input = element.find(selector).addBack(selector); // find, including element itself
this.idForLabel = idForLabel;
this.setState(initialState);
}
getValue() {
return this.input.val();
}
getState() {
return this.input.val();
}
setState(state) {
this.input.val(state);
}
getTextLabel(opts) {
const val = this.getValue();
if (typeof val !== 'string') return null;
const maxLength = opts && opts.maxLength;
if (maxLength && val.length > maxLength) {
return val.substring(0, maxLength - 1) + '…';
}
return val;
}
focus() {
this.input.focus();
}
}
// my code here:
class AdminTagWidget {
constructor(html, idPattern) {
this.html = html;
this.idPattern = idPattern;
}
boundWidgetClass = BoundWidget;
render(placeholder, name, id, initialState) {
console.log("RENDER", placeholder, name, id, initialState); // this does not show
var html = this.html.replace(/__NAME__/g, name).replace(/__ID__/g, id);
var idForLabel = this.idPattern.replace(/__ID__/g, id);
var dom = $(html);
$(placeholder).replaceWith(dom);
// eslint-disable-next-line new-cap
return new this.boundWidgetClass(dom, name, idForLabel, initialState);
}
}
console.log("here") // does show in the console
// variants I've tried:
//window.telepath.register('wagtail.admin.widgets.tags.AdminTagWidget', AdminTagWidget);
//window.telepath.register('wagtail.widgets.AdminTagWidget', AdminTagWidget);
window.telepath.register('path.where.its.used.AdminTagWidget', AdminTagWidget)
The log from my custom render method does not show. It seems that I'm not calling the right path within window.telepath.register but I don't know how what the string is supposed to be...
I'm not even sure if this is the right way forward.
Notes:
it works in regular field, the question is about tags in blocks
I'm using Wagtail version 2.13.2 but I've also tried with 2.15 without any difference.
In the console, I can log window.telepath and see my custom widget. It's just not "applied" to anything
Your WidgetAdapter class needs a js_constructor attribute:
class AdminTagWidgetAdapter(WidgetAdapter):
js_constructor = 'myapp.widgets.AdminTagWidget'
class Media:
js = [
"wagtailadmin/js/vendor/tag-it.js",
"js/admin/admin-tag-widget-adapter.js",
]
Any string value will work here - it just needs to uniquely identify the class, so it's recommended to use a dotted module-like path to avoid colliding with others. This then matches the string you pass to window.telepath.register on the Javascript side:
window.telepath.register('myapp.widgets.AdminTagWidget', AdminTagWidget)

How does one get the id from the globalState in a Visual Studio Code extension?

Within the vscode extension context, there's globalState. globalState is an ExtensionMemento object, and at runtime while debugging I can see that it has a private _id.
How do I obtain the id? I've tried:
context.globalState.get<string>("id");
context.globalState.get<string>("_id");
...but each return undefined.
When the extension is activated, the current extension context is passed as argument. You may use the context.extensionPath to find package.json and parse it.
import * as Path from 'path';
import * as fs from 'fs';
export function activate(context: vscode.ExtensionContext) {
var extensionPath = Path.join(context.extensionPath, "package.json");
var packageFile = JSON.parse(fs.readFileSync(extensionPath, 'utf8'));
if (packageFile) {
var packageId = packageFile.publisher + '.' + packageFile.name;
console.log(packageId);
}
//......... rest
}
context.globalState["_id"]

Protractor: use variable from helper file in spec file

I have perhaps unusual situation where I have to get text out of an element in a helper file and then compare this text in spec file. For example:
Both page files:
this.matchText = function(elem) {
return elem.getText();
};
Helper file:
// page objects
var calculationPage = require('../calculation_page/calculation_page.js');
// variables
var globalPrice = "";
module.exports = exports = function() {
describe('...
it('...
// initialize page object
var calculation = new calculationPage();
// store price into global variable
calculation.matchText(calculation.price).then(function(text) {
globalPrice = text;
});
// verify price equals expected
expect(calculation.matchText(calculation.priceSum)).toContain(globalPrice);
???
});
});
}
How to store globalPrice as a variable that could be passed to spec file?
Spec file:
// page objects
var homePage = require('../home_page/home_page.js');
// helpers
var getPrice = require('../helpers/get_price.js');
describe('...
it('...
// helper - get price
getPrice();
// initialize page object
var home = new homePage();
// verify if price equals expected
expect(home.matchText(home.price)).toContain(???);
});
});
How to read global variable from helper file in spec file?
You can dump any values you need globally onto Protractor global object - browser.
Lets say .. in helper file you need to store the value. Then do this - browser.globalPrice = text
And then this value would be available in your spec file. Access it from the browser object like any other value expect(home.matchText(home.price)).toContain(browser.globalPrice);
Please refer my answer #Protractor: initialise Global variable in one js and use the same var in other js

How to Listen Keys in JScript.Net

What I wish is to catch the keypress using JScript .NET, and compile the code using that jsc.exe.
So, is there any equivalent of "addEventListener("keyDown", keyCheck)" from FLASH actionscript. Or GetAsyncKeyState() from C++.
And what library do I have to use?
Please be kind enough to share a small, simple example.
Here's a simple solution if you're writing a console app.
import System;
Console.Write("Press the M key... ");
var key:ConsoleKeyInfo;
while (1) {
while (!Console.KeyAvailable) {
System.Threading.Thread.Sleep(1);
}
key = Console.ReadKey(1);
if (key.Key == ConsoleKey.M) break;
}
Console.Write("Accepted.");
Read more about ConsoleKeyInfo.
If you need GetAsyncKeyState(), it is possible to access the method in JScript.NET. A couple days ago I came across a JScript.NET function that exposes Win32 API methods via P/Invoke. Here it is, slightly modified for simpler syntax (allowing pass-through of arguments from API function definitions).
import System;
import System.Reflection;
import System.Reflection.Emit;
// Invoke a Win32 P/Invoke call.
// credit: http://cx20.main.jp/blog/hello/2013/03/07/hello-win32-api-jscript-net-world/
function InvokeWin32(dllName:String, returnType:Type, methodName:String, params:Object[]) {
var paramTypes:Type[] = new Type[params.length];
for (var i:int in params) {
paramTypes[i] = params[i].GetType();
}
// Begin to build the dynamic assembly
var domain = AppDomain.CurrentDomain;
var name = new System.Reflection.AssemblyName('PInvokeAssembly');
var assembly = domain.DefineDynamicAssembly(name, AssemblyBuilderAccess.Run);
var module = assembly.DefineDynamicModule('PInvokeModule');
var type = module.DefineType('PInvokeType',TypeAttributes.Public
+ TypeAttributes.BeforeFieldInit);
// Define the actual P/Invoke method
var method = type.DefineMethod(methodName, MethodAttributes.Public
+ MethodAttributes.HideBySig + MethodAttributes.Static +
MethodAttributes.PinvokeImpl, returnType, paramTypes);
// Apply the P/Invoke constructor
var ctor = System.Runtime.InteropServices.DllImportAttribute.GetConstructor(
[System.String]
);
var attr = new System.Reflection.Emit.CustomAttributeBuilder(ctor, [dllName]);
method.SetCustomAttribute(attr);
// Create the temporary type, and invoke the method.
var realType = type.CreateType();
return realType.InvokeMember(methodName, BindingFlags.Public + BindingFlags.Static
+ BindingFlags.InvokeMethod, null, null, params);
}
With this function, you can expose Win32 DLL methods with the following syntax. (See? Told you it was simpler.)
// ShowWindowAsync(hWnd:IntPtr, nCmdShow:int);
function ShowWindowAsync(... args:Object[]):boolean {
return InvokeWin32("user32.dll", System.Boolean, "ShowWindowAsync", args);
}
// GetWindowLong(hWnd:IntPtr, nIndex:int);
function GetWindowLong(... args:Object[]):int {
return InvokeWin32("user32.dll", System.Int32, "GetWindowLong", args);
}
// FindWindowEx(parentHandle:IntPtr, childAfter:IntPtr,
// lclassName:IntPtr, windowTitle:String);
function FindWindowEx(... args:Object[]):IntPtr {
return InvokeWin32("user32.dll", System.IntPtr, "FindWindowEx", args);
}
And I've never used GetAsyncKeyState(); but since it's a user32.dll method, I'm guessing it'll work the same way. (Edit: It does.)
// GetAsyncKeyState(vKey:int);
function GetAsyncKeyState(... args:Object[]):short {
return InvokeWin32("user32.dll", System.Int16, "GetAsyncKeyState", args);
}
Then for a trivial example:
import System; // for Console methods
import System.Windows.Forms; // for Keys object constants
Console.Write("Press the M key... ");
// while the M key is not being pressed, sleep
while (!GetAsyncKeyState(Keys.M)) {
System.Threading.Thread.Sleep(1);
}
// flush input buffer
while (Console.KeyAvailable) Console.ReadKey(1);
Console.WriteLine("Accepted.");