VSCode - IntelliSense with custom languages - tokenize

Hello VS Code Community!
I'm currently extending the VS Code editor with a own / custom language. This is easier as I thought but now I'm getting problems with IntelliSense.
As you can see, VS Code is suggesting me the content of comments and strings and that's the big problem for me.
I'm inexperienced to this and learning by trying ;) I guess it has to do with tokenizer but I have no idea how to specify / exclude comments and variable values.
Normally only declared variables and the given keywords should be suggested
Here the relevant code: (only for learning purposes, no copyright infringement intended)
/*---------------------------------------------------------
* Copyright (C) Microsoft Corporation. All rights reserved.
*--------------------------------------------------------*/
/// <reference path="../../declares.d.ts" />
'use strict';
define(["require", "exports", '../sqfDef', 'monaco-testing'], function (require, exports, languageDef, T) {
var tokenizationSupport = T.createTokenizationSupport(languageDef.language);
var tokenize = T.createTokenizeFromSupport(tokenizationSupport);
var assertTokens = T.assertTokens;
T.module('Syntax Highlighting - SQF');
}
Are there any docs or can someone explain me please how to exclude this from the suggested list?
EDIT:
Ok, I realised that you can define object types in the Def.js so defining them in the Tests.js is not necessary. yet my problem persists.

Since there is currently no documentation for writing custom plugins we all gather our information by reverse engineering.
Take a look at resources\app\plugins\vs.language.typescript\features\suggestSupport.js. In line 10 you find this this.excludeTokens = ['string', 'comment', 'numeric'];.
So you need to write your own suggestSupport.js and register it in your languageMain.js.
You find an example setting it up in resources\app\plugins\vs.language.typescript\typescriptMain.js in line 58:
var suggestSupport = new SuggestSupport(ctx, client);
monaco.Modes.SuggestSupport.register(MODE_ID, suggestSupport);
return Configuration.load(MODE_ID, ctx.configurationService).then(function (config) {
suggestSupport.setConfiguration(config);
});

Related

Detect the first time a VS Code extension version is loaded

I'd like to take an action the first time a user loads a new version of my VS Code extension. This is different from merely detecting first run as described by the How to run vscode extension command just right after installation? because I don't want to detect "just right after installation" I want to detect first run of each new version which is a totally different problem.
Mike Lischke's answer to that question doesn't actually answer that question, it answers this question, but that doesn't mean this is a duplicate question, it means the response to the other question doesn't actually answer the asked question, and since unlike many people I actually read the question, I didn't bother to read the answers, because answers to that question are not what I seek. Frankly I'm tempted to delete the question myself just to spite Stack Overflow because I'm fed up with this crap. Do whatever you like.
Searching the net turned up sample code
export function activate(context: vscode.ExtensionContext) {
if (context.firstTimeUse) {
//do the one-time-per-version-update thing
}
}
but ExtensionContext doesn't seem to have this property, at least not any more.
So how do you do it now?
I could record the version in a file and compare to the file before updating it, but if there's baked in support I'd rather do it the supported way.
There is no supported mechanism.
Since each update gets a new folder, you don't need to log a timestamp, just probe for the file. If it exists, not first run. If it doesn't exist, first run so create the file and do other first run things.
This is so simple and straightforward there probably won't ever be a supported mechanism. Thanks to Lex Li in the comments for confirming that this is the standard solution.
If you need to differentiate major, minor and maintenance releases, the simplest solution is to store the version string in context.globalState. You begin by trying to fetch from context.globalState. Absence means first run ever. If it's present, an exact match for current version means no change. For a non-match you can parse out major and minor version numbers context.globalState.
const currentVersion = context.extension.packageJSON.version as string;
const lastVersion = context.globalState.get("version") as string ?? "0.0.0"
if (lastVersion !== currentVersion) {
logger.warn(`Updated to ${currentVersion}`);
const lastVersionPart = lastVersion.split(".");
const currVersionPart = currentVersion.split(".");
if (lastVersionPart[0] !== currVersionPart[0]) {
// major version change
advertiseWalkthrough();
if (lastVersionPart[1] !== currVersionPart[1]) {
// minor version change
launchWhatsNew();
} else {
// it's a maintenance version change so don't pester the user
}
}
context.globalState.update("version", currentVersion);
}

Getting FusionAuthClient is not a constructor error

I am trying the fusionauth-node-client and following the wiki https://fusionauth.io/docs/v1/tech/client-libraries/node. But I am getting the following error
const client = new FusionAuthClient('6b87a398-39f2-4692-927b-13188a81a9a3', 'http://localhost:9011');
^
TypeError: FusionAuthClient is not a constructor
at Object.<anonymous>
I have pasted the exact code mentioned in the doc still it is not working. Can anyone help me in identifying what I am missing here.
I dug around in the library and noticed that we are exporting several objects and our example is no longer correct.
To get the client you need to change your syntax a little bit to get the correct object.
const {FusionAuthClient} = require('fusionauth-node-client');
This translates to: require the library fusionauth-node-client and give me the FusionAuthClient from inside it. There are also a RESTClient and JWTManager available in the library but you shouldn't need either of those to code with FusionAuth.
I will also update our example to correct this discrepancy.

Upgrade from .net 4 to 4.5 breaks Html.Raw call in Javascript

I have the following code in a c# MVC 3 razor page where I am passing serialized data into a javascript variable for KnockoutJs:
#{
var listData = new JavaScriptSerializer().Serialize(Model.ListItems);
var pagerData = new JavaScriptSerializer().Serialize(Model.Pager);
}
// additional code
<script type="text/javascript" >
var ListData = #(Html.Raw(listData)); // <-- Syntax Error here
var PagerData = #(Html.Raw(pagerData)); // <-- Syntax Error here
// additional js code
</script>
After upgrading to VS 2012, I am getting error squiggles after the javascript semi-colons at the end the Html.Raw lines above. The project complies but VS 2012 displays 'Syntax Error' in the Error List for each line. Without the semi-colons the javascript also shows a 'Syntax Error'.
This code worked without issues in the previous version. Is this a bug in the VS 2012 parser and is there a way to avoid the generated errors?
Edit
Anyone else seeing this issue? Below is a simplified version with the same issue isolated in a new page. If you add a semi-colon at the end of the ListData line you get a javascript syntax error, without one it is on the next line. Is this a bug in the javascript compiler between VS2010 and VS2012?
#{
var listData = "test";
var pagerData = "test2";
}
<script type="text/javascript" >
var ListData = #(Html.Raw(listData))
var PagerData = #(Html.Raw(pagerData))
</script>
Please add vote on this connect issue. We will address this issue in next version of VS. I have attached your repro code to this bug and added link to this post as another manifestation of the issue.
This issue still exist in Visual Studio 2013 SP 2
To fix this warning message initialize javascript variable first. IMO Visual studio think var as implicitly typed if any var followed by #.
var ListData;
var PagerData;
ListData = #(Html.Raw(listData));
PagerData = #(Html.Raw(pagerData));
I'm using MVC5 and finding the same issue, so I solved it this way, which should work in all versions
#Html.Raw("var myData = " + Json.Encode(this.Model.MyData) + ";" )
However, I would use this only in the simplest situations since you lose any intellisense as to VAR type (although it does treat it as a global instance and the compiler doesn't throw a wobbler), so for now I think an initial, empty definition is probably the best way to proceed.
I have had the same thing happen, but it does so at random.
What I have tried to resolve it is the following:
Make sure you can compile/build/debug in Debug mode, switch to Release mode and attempt to debug/publish from that mode.
Switch back to Debug mode and re-attempt the publish.
Some combination of switching modes does the trick, I just can'y nail down what it is exactly.
Once you get it working, don't close VS ;-)
Let's hope MS gets this fixed in SP1.

Using System.Reflection and resources in Phalanger

I need to embed some resource in a pure compiled dll written in php using phalanger.
These are txt files tha I set in visual studio as "Embedded Resource".
My problem is that I cannot use the Assembly class to get the resource using GetManifestResourceStream.
I tried code like this:
use System\Reflection\Assembly
$asm = Assembly::GetExecutingAssembly(); //this gives me mscorlib instead of my dll
$str = $asm->GetManifestResourceStream("name");
My question is: how do I get access to embedded resources in phalanger?
Many thanks
I'm not sure, why Assembly::GetExecutingAssembly() returns an incorrect value. Anyway to workaround the $asm value, use following code:
$MyType = CLRTypeOf MyProgram;
$asm = $MyType->Assembly;
Then you can access embedded resources as you posted
$asm->GetManifestResourceStream("TextFile1.txt");
or you can include standard resource file (.resx) into your project, and use \System\Resources\ResourceManager
$this->manager = new \System\Resources\ResourceManager("",$asm);
$this->manager->GetObject("String1",null);
Just note, currently there can be just one .resx within Phalanger project
This question is old, but the part of the Phalanger code (Php.Core.Emit.AddResourceFile() method) responsible for this hasn't changed since this was asked. I faced the same problem and solved it in (almost) non-hacky way. You have to provide alternative name (/res:/path/to/filename,alternative-name) for this to work though.
$asm = clr_typeof('self')->Assembly;
$resourceStream = $asm->GetManifestResourceStream("filename");
$reader = new \System\Resources\ResourceReader($resourceStream);
$type = $data = null;
$reader->GetResourceData("alternative-name", $type, $data);
// and still there are 4 excess bytes
// representing the length of the resource
$data = \substr($data, 4);
$stream = new IO\MemoryStream($data);
// after this $stream is usable as you would expect
Straightforward GetManifestResourceStream() (as suggested by Jakub) does not work because Phalanger does not use System.Reflection.Emit.ModuleBuilder.DefineManifestResource() (like I think it should when supplied with unrecognized file format). It uses ModuleBuilder.DefineResource() which returns ResourceWriter instead, that only really suited for .resources files. And this is what dictates the requirement to use ResourceReader when you need to read your resource.
Note: This answer applies to Phalanger master branch at the time of writing and prior versions since circa 2011. Noted because it looks like a bug (especially the need to use both original and alternative names).

C++ Builder XE2, TXMLDocument 'DTD is prohibited'

When I try to read an XML document (eagle file) with an DTD I get the error:
Project xx raised exception class EDOMParserError with message 'DTD is
prohibited'
The XML header looks like this:
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE eagle SYSTEM "eagle.dtd">
If I remove the second line...
<!DOCTYPE eagle SYSTEM "eagle.dtd">
...everything works fine.
After some googling it seems like the MSXML parser have an option called ´prohibitDTD´ set to true by default (in earlier versions it was false).
However it seems not possible to set this option to false from the TXMLDocument class. One solution seems to be a recompile of the .pas library or to create the interface on my own with CoCreateInstance().
All examples I have seen out there are in Delphi and I'm having dificulties to trasnlate these to C++ Builder.
Does anyone know how to read a DTD XML document with C++ Builder XE2?
My example code...
#include <xmldoc.hpp>
_di_IXMLNode XMLObject;
TXMLDocument *XMLDocument = new TXMLDocument(this);
XMLDocument->LoadFromFile(fileName); // <----- Exception EDOMParserError
XMLObject = XMLDocument->DocumentElement;
Thank you...
XE2 introduced a native solution to this very problem: there is a global bool variable named MSXML6_ProhibitDTD declared in Xml.Win.msxmldom.hpp. You can set it to false before loading data into TXMLDocument:
#include <xmldoc.hpp>
#include <msxmldom.hpp>
MSXML6_ProhibitDTD = false;
TXMLDocument *XMLDocument = new TXMLDocument(this):
XMLDocument->LoadFromFile(fileName);
_di_IXMLNode XMLObject = XMLDocument->DocumentElement;
On a side note: it is generally not a good idea to create TXMLDocument instances dynamically like this. It is better to use the IXMLDocument interface instead:
#include <xmldoc.hpp>
#include <msxmldom.hpp>
MSXML6_ProhibitDTD = false;
_di_IXMLDocument XMLDocument = LoadXMLDocument(fileName);
_di_IXMLNode XMLObject = XMLDocument->DocumentElement;
Since the workaround with the global variable MSXML6_ProhibitDTD is deprecated and I couldn't get it to work with XE5 either, here is another solution:
As stated in the documentation, there is this method to change the DOM property
Xml.Win.Msxmldom.MSXMLDOMDocumentFactory.AddDOMProperty
Unfortunately it's not so trivial to use this...
include the header for this namespace:
#include <Xml.Win.msxmldom.hpp>
Foo::Foo()
{
//change the dom property in your constructor.
((TMSXMLDOMDocumentFactory*)Xml::Win::Msxmldom::MSXMLDOMDocumentFactory)->AddDOMProperty("ProhibitDTD", False, true);
}
and access this method. (The cast is necessary, because the MSXMLDOMDocumentFactory itself is inherited from a metaclass interface or so. I don't got the concept behind.)
inspired from a delphi blog: https://bobsotherblog.wordpress.com/2013/09/19/fixing-dtd-is-prohibited-error-in-delphi/
You need to copy MSXMLDOM.pas into your project folder, and modify it in order to fix this issue.
Change the implementation of function TMSDOMDocument.GetMSDocument to the following, and then rebuild your project.
Note you have to use IXMLDOMDocument2.setProperty instead of accessing ProhibitDTD directly, as IXMLDOMDocument2 doesn't publish ProhibitDTD.
function TMSDOMDocument.GetMSDocument: IXMLDOMDocument;
var
Doc2: IXMLDOMDocument2;
begin
Result := MSNode as IXMLDOMDocument;
if Supports(Result, IXMLDOMDocument2, Doc2) then
Doc2.setProperty('ProhibitDTD', False);
end;
Note that this will only work if you're not building with runtime packages!
This solution is from an Embarcadero forums post made by a member of TeamB; I remembered reading it, and found it in a search of those forums via CodeNewsFast - search functionality at the EMBT forums hasn't ever worked well, and a recent rebuild or reindex or something has made it even worse than before. :-)