I am running a callback on the workspace.onWillSaveTextDocument handler. It provides vscode.TextDocument and this is necessary for the work I want to do on this event.
In certain cases, I want to treat other files (that aren't currently open) as if they had just been saved, as well.
It would suffice to be able to create a new instance of vscode.TextDocument, but I was unable to figure that out.
Is there a way to do something like:
workspace.pretendThisWasSavedJustNow('/path/to/other/file.ts');
I work on VSCode and while I don't know your exact use case, I believe you are looking for workspace.openTextDocument.
To use the same function for workspace.onWillSaveTextDocument and on some other event that your extension triggers, try something like:
// Actual save
workspace.onWillSaveTextDocument(e => onDocumentSave(e.document))
// Emulated save
setInterval(() => {
workspace.openTextDocument('path/to/other/file.ts')
.then(document => onDocumentSave(document))
}, 5000)
// Common save handling implementation
function onDocumentSave(document: TextDocument) { ... }
Related
I am working on a VsCode extension in that I want to provide custom snippets for code completion.
I know about the option of using snippet json files directly, however those have the limitation of not being able to utilize the CompletionItemKind property that determines the icon next to the completion suggestion in the pop-up.
My issue:
If I implement a simple CompletionItemProvider like this:
context.subscriptions.push(
vscode.languages.registerCompletionItemProvider(
{scheme:"file",language:"MyLang"},
{
provideCompletionItems(document: vscode.TextDocument, position: vscode.Position) {
let item = new vscode.CompletionItem('test');
item.documentation = 'my test function';
item.kind = vscode.CompletionItemKind.Function;
return [item];
}
}
)
)
then the original VsCode IntelliSense text suggestions are not shown anymore, only my own. Should I just return a kind of an empty response, like
provideCompletionItems(document: vscode.TextDocument, position: vscode.Position) {
return [null|[]|undefined];
}
the suggestions appear again as they should. It seems to me that instead of merging the results of the built-in IntelliSense and my own provider, the built-in ones get simply overridden.
Question:
How can I keep the built-in IntelliSense suggestions while applying my own CompletionItems?
VsCode Version: v1.68.1 Ubuntu
I seem to have found the answer for my problem, so I will answer my question.
Multiple providers can be registered for a language. In that case providers are sorted
by their {#link languages.match score} and groups of equal score are sequentially asked for
completion items. The process stops when one or many providers of a group return a
result.
My provider seems to provide results that are just higher scored than those of IntelliSense.
Since I didn't provide any trigger characters, my CompletionItems were comteping directly with the words found by the built-in system by every single pressed key and won.My solution is to simply parse and register the words in my TextDocument myself and extend my provider results by them. I could probably just as well create and register a new CompletionItemProvider for them if I wanted to, however I decided to have a different structure for my project.
I have a problem with some dynamically generated forms and passing values to them. I feel like someone must have solved this, or I’m missing something obvious, but I can't find any mention of it.
So for example, I have three components, a parent, a child, and then a child of that child. For names, I’ll go with, formComponent, questionComponent, textBoxComponent. Both of the children are using changeDetection.OnPush.
So form component passes some values down to questionComponent through the inputs, and some are using the async pipe to subscribe to their respective values in the store.
QuestionComponent dynamically creates different components, then places them on the page if they match (so many types of components, but each questionComponent only handles on one component.
some code:
#Input() normalValue
#Input() asyncPipedValue
#ViewChild('questionRef', {read: ViewContainerRef}) public questionRef: any;
private textBoxComponent: ComponentFactory<TextBoxComponent>;
ngOnInit() {
let component =
this.questionRef.createComponent(this.checkboxComponent);
component.instance.normalValue = this.normalValue;
component.instance. asyncPipedValue = this. asyncPipedValue;
}
This works fine for all instances of normalValues, but not for asyncValues. I can confirm in questionComponent’s ngOnChanges that the value is being updated, but that value is not passed to textBoxComponent.
What I basically need is the async pipe, but not for templates. I’ve tried multiple solutions to different ways to pass asyncValues, I’ve tried detecting when asyncPipeValue changes, and triggering changeDetectionRef.markForChanges() on the textBoxComponent, but that only works when I change the changeDetectionStrategy to normal, which kinda defeats the performance gains I get from using ngrx.
This seems like too big of an oversight to not already have a solution, so I’m assuming it’s just me not thinking of something. Any thoughts?
I do something similar, whereby I have forms populated from data coming from my Ngrx Store. My forms aren't dynamic so I'm not 100% sure if this will also work for you.
Define your input with just a setter, then call patchValue(), or setValue() on your form/ form control. Your root component stays the same, passing the data into your next component with the async pipe.
#Input() set asyncPipedValue(data) {
if (data) {
this.textBoxComponent.patchValue(data);
}
}
patchValue() is on the AbstractControl class. If you don't have access to that from your question component, your TextBoxComponent could expose a similar method, that can be called from your QuestionComponent, with the implementation performing the update of the control.
One thing to watch out for though, if you're also subscribing to valueChanges on your form/control, you may want to set the second parameter so the valueChanges event doesn't fire immediately.
this.textBoxComponent.patchValue(data, { emitEvent: false });
or
this.textBoxComponent.setValue(...same as above);
Then in your TextBoxComponent
this.myTextBox.valueChanges
.debounceTime(a couple of seconds maybe)
.distinctUntilChanged()
.map(changes => {
this.store.dispatch(changes);
})
.subscribe();
This approach is working pretty well, and removes the need to have save/update buttons everywhere.
I believe I have figured out a solution (with some help from the gitter.com/angular channel).
Since the values are coming in to the questionComponent can change, and trigger it's ngOnChanges to fire, whenever there is an event in ngOnChanges, it needs to parse through the event, and bind and changes to the dynamic child component.
ngOnChanges(event) {
if (this.component) {
_.forEach(event, (value, key) => {
if (value && value.currentValue) {
this.component.instance[key] = value.currentValue;
}
});
}
}
This is all in questionComponent, it resets the components instance variables if they have changed. The biggest problem with this so far, is that the child's ngOnChanges doesn't fire, so this isn't a full solution. I'll continue to dig into it.
Here are my thoughts on the question, taking into account limited code snippet.
First, provided example doesn't seem to have anything to do with ngrx. In this case, it is expected that ngOnInit runs only once and at that time this.asyncPipedValue value is undefined. Consequently, if changeDetection of this.checkboxComponent is ChangeDetection.OnPush the value won't get updated. I recommend reading one excellent article about change detection and passing async inputs. That article also contains other not less great resources on change detection. In addition, it seems that the same inputs are passed twice through the component tree which is not a good solution from my point of view.
Second, another approach would be to use ngrx and then you don't need to pass any async inputs at all. Especially, this way is good if two components do not have the parent-child relationship in the component tree. In this case, one component dispatches action to put data to Store and another component subscribes to that data from Store.
export class DataDispatcherCmp {
constructor(private store: Store<ApplicationState>) {
}
onNewData(data: SomeData) {
this.store.dispatch(new SetNewDataAction(data));
}
}
export class DataConsumerCmp implements OnInit {
newData$: Observable<SomeData>;
constructor(private store: Store<ApplicationState>) {
}
ngOnInit() {
this.newData$ = this.store.select('someData');
}
}
Hope this helps or gives some clues at least.
I have a few policies that I'm trying to convert to installable hooks.
One in particular is the authentication step that adds a session variable for who the user is. I need to ensure that it fires first because subsequent hooks/controllers look at the session to determine who the user is.
The docs on routes ( https://github.com/balderdashy/sails-docs/blob/master/concepts/extending-sails/Hooks/hookspec/routes.md ) say that I can specify if I want to run the route before or after all the custom routes, but I don't see a way to specify one hook before another hook.
I tried adding a "sails.on" in the initialize step of my two hooks as specified in the initialize docs ( https://github.com/balderdashy/sails-docs/blob/master/concepts/extending-sails/Hooks/hookspec/initialize.md ). While it did alter the order of the initialize phase, it didn't seem to have any impact on the order that routes were handled.
Any pointers would be greatly appreciated.
As you noted, there's no way to re-order hooks at the moment, but that doesn't mean you can't accomplish your goal in another way. The routes feature of hooks is very convenient, but in this case you will need to bind your routes using events, and then make your hooks dependent on each other to ensure that the routes load in the correct order. Many of the core Sails hooks work in just this way.
If you want to ensure that the hook firsthook to loads all of its routes before secondhook, you would put the following as the initialize method of firsthook:
initialize: function(cb) {
sails.on('router:before', function () {
sails.router.bind(routePath1, routeFn1);
sails.router.bind(routePath2, routeFn2);
sails.router.bind(routePath3, routeFn3);
etc...
});
}
And then do the same in secondhook, but wrapped in a sails.after block:
initialize: function(cb) {
sails.after('hook:firsthook:loaded', function() {
sails.on('router:before', function () {
sails.router.bind(routePath1, routeFn1);
sails.router.bind(routePath2, routeFn2);
sails.router.bind(routePath3, routeFn3);
etc...
});
}
}
Note that sails.after can accept either a single event name or an array to wait for.
I am using jQuery 1.9.1.
Suppose i have a button with id="clickMe"
My jQuery code is:
$('#clickMe').click(function(event)
{
eventHandler1();//do something
eventHandler2();//use output from eventHandler1() and do something
}
Now, i want "eventHandler2" to be executed at last so that i could use the output of "eventHandler1". Is there any way to do this manually and not just the way i have put the handlers inside the click event?
One more thing, "eventHandler1()" and "eventHandler2()" are present in different .js files and thus the requirement.
jQuery.when() provides a way to execute callback functions based on one or more objects, usually Deferred objects that represent asynchronous events.
For example, when the Deferreds are jQuery.ajax() requests, the arguments will be the jqXHR objects for the requests, in the order they were given in the argument list.
$.when(eventHandler1).then(eventHandler2).done(function(){
alert('done.');
});
So can even use GLOBAL variable to store eventHandler1 output and access that inside eventHandler2
Example
var someVar;
function eventHandler1()
{
// process
someVar = some value from process
return someVar;
}
function eventHandler2()
{
alert(someVar);
}
Response to OP comment
as you have asked about execute handler in queue you can use Jai answer.
you can use .when .then and .done as below.
$.when(eventHandler1).then(eventHandler2).done(function(){
//process code
});
I've been looking for a script that combines the autoGrowInput with the JEditable but found none.
Use https://github.com/MartinF/jQuery.Autosize.Input initialized automatically via jEditable's event data:
jQuery(element).editable(save_fn, {
data: function(value,settings} {
var target = event.target;
window.setTimeout(function(){
jQuery(target).find('input').autosizeInput();
});
return value;
}
});
It's worth noting that this event (data) fires before the input element is actually created, hence the use of the timeout. There doesn't seem to be an event available at the present time for after the input has been created.
Actually I have created a plugin that does exactly that. You can check the demo and the documentation. I tried to make it very intuitive. It has ajax capabilities, using the RESTful philosophy. If you liked the animation effect on the autoGrowInput, it will be really easy to add it to the plugin just by changing the css file, using the transition property.
If I get people to like it, I may be able to improve and add more features to it. Hope it helps.