Can text / snippet to be inserted by Atom autocomplete+ be provided asynchronously? - asynchronous

I am writing an extension for Atom's autocomplete+ plugin, following the Provider API described at https://github.com/atom/autocomplete-plus/wiki/Provider-API.
The getSuggestions function can be implemented asynchronously by returning a promise.
Is it also possible to fetch the text or snippet to be inserted into the editor after the user selects an autocomplete-entry asynchronously?
In my use case, I want to fetch the text to insert into the editor only after the user makes a choice, and not already when fetching (a possibly larger number of) suggestions in getSuggestions.

Late response, but I think this is doable.
General idea is to let Atom do the suggestion insertion with text as normal (text doesn't matter, can be a placeholder). Then handle onDidInsertSuggestion() to immediately undo the insertion. Then use your own Promise to async fetch the actual text and insert it manually. You can use setTextInBufferRange() to do this.
I did a similar thing to handle suggestion insertion manually (minus the async part). Maybe this can help you get started: https://github.com/lonekorean/atom-autocomplete-math/blob/master/lib/provider.js#L92
Word of caution, async means there could be a delay between the request for text and the text being inserted. If the user is a fast typer or the internet connection is terrible, weird things might happen.

Related

Meteor - subscribe to same collection twice - keep results separate?

I have a situation in which I need to subscribe to the same collection twice. The two publish methods in my server-side code are as follows:
Meteor.publish("selected_full_mycollection", function (important_id_list) {
check(important_id_list, Match.Any); // should do better check
// this will return the full doc, including a very long array it contains
return MyCollection.find({
important_id: {$in: important_id_list}
});
});
Meteor.publish("all_brief_mycollection", function() {
// this will return all documents, but only the id and first item in the array
return MyCollection.find({}, {fields: {
important_id: 1,
very_long_array: {$slice: 1}
}});
});
My problem is that I am not seeing the full documents on the client end after I subscribe to them. I think this is because they are being over-written by the method that publishes only the brief versions.
I don't want to clog up my client memory with long arrays when I don't need them, but I do want them available when I do need them.
The brief version is subscribed to on startup. The full version is subscribed to when the user visits a template that drills down for more insight.
How can I properly manage this situation?
TL/DR - skip to the third paragraph.
I'd speculate that this is because the publish function thinks that the very_long_array field has already been sent to the client, so it doesn't send it again. You'd have to fiddle around a bit to confirm this, but sending different data on the same field is bound to cause some problems.
In terms of subscribing on two collections, you're not supposed to be able to do this as the unique mongo collection name needs to be provided to the client and server-side collections object. In practice, you might be able to do something really hacky by making one client subscription a fake remote subscription via DDP and having it populate a totally separate Javascript object. However, this cannot be the best option.
This situation would be resolved by publishing your summary on something other than the same field. Unfortunately, you can't use transforms when returning cursors from a publish function (which would be the easiest way), but you have two options:
Use the low-level publications API as detailed in this answer.
Use collection hooks to populate another field (like very_long_array_summary) with the first item in the array whenever very_long_array changes and publish just the summary field in the former publication.
A third option might be publishing the long version to a different collection that exists for this purpose on the client only. You might want to check the "Advanced Pub/Sub" Chapter of Discover Meteor (last sub chapter).

What Class/Method's is used to write to the SysOutGoingEmailTable from an alert notification?

When creating an alert you can setup if you want the user to receive an email when the alert happens. What class/method deals with writing the record to the SysOutGoingEmailTable.I thought the EventActionEmail class would be used, specifically the execute method, which in return calls SysEmailTable::sendMail() to insert a record into the SysOutGoingEmailTable. After doing some editing on the EventActionEmail Class and adding some info-log's for testing purposes it seems that the Class isn't even being used to write to the outgoing table.
It IS \Classes\EventActionEmail\execute that does the emails. Have you rebuilt your CIL after adding your infologs? Where are you looking for the infologs? I'd think the BatchJobHistory form (log button) would be where to start.

Is there a way to tell meteor a collection is static (will never change)?

On my meteor project users can post events and they have to choose (via an autocomplete) in which city it will take place. I have a full list of french cities and it will never be updated.
I want to use a collection and publish-subscribes based on the input of the autocomplete because I don't want the client to download the full database (5MB). Is there a way, for performance, to tell meteor that this collection is "static"? Or does it make no difference?
Could anyone suggest a different approach?
When you "want to tell the server that a collection is static", I am aware of two potential optimizations:
Don't observe the database using a live query because the data will never change
Don't store the results of this query in the merge box because it doesn't need to be tracked and compared with other data (saving memory and CPU)
(1) is something you can do rather easily by constructing your own publish cursor. However, if any client is observing the same query, I believe Meteor will (at least in the future) optimize for that so it's still just one live query for any number of clients. As for (2), I am not aware of any straightforward way to do this because it could potentially mess up the data merging over multiple publications and subscriptions.
To avoid using a live query, you can manually add data to the publish function instead of returning a cursor, which causes the .observe() function to be called to hook up data to the subscription. Here's a simple example:
Meteor.publish(function() {
var sub = this;
var args = {}; // what you're find()ing
Foo.find(args).forEach(function(document) {
sub.added("client_collection_name", document._id, document);
});
sub.ready();
});
This will cause the data to be added to client_collection_name on the client side, which could have the same name as the collection referenced by Foo, or something different. Be aware that you can do many other things with publications (also, see the link above.)
UPDATE: To resolve issues from (2), which can be potentially very problematic depending on the size of the collection, it's necessary to bypass Meteor altogether. See https://stackoverflow.com/a/21835534/586086 for one way to do it. Another way is to just return the collection fetch()ed as a method call, although this doesn't have the benefits of compression.
From Meteor doc :
"Any change to the collection that changes the documents in a cursor will trigger a recomputation. To disable this behavior, pass {reactive: false} as an option to find."
I think this simple option is the best answer
You don't need to publish your whole collection.
1.Show autocomplete options only after user has inputted first 3 letters - this will narrow your search significantly.
2.Provide no more than 5-10 cities as options - this will keep your recordset really small - thus no need to push 5mb of data to each user.
Your publication should look like this:
Meteor.publish('pub-name', function(userInput){
var firstLetters = new RegExp('^' + userInput);
return Cities.find({name:firstLetters},{limit:10,sort:{name:1}});
});

How to manipulate the data pointed by a cursor before render it

everybody.
I have a doubt in this portion of my system: I want to encrypt some messages from users to the database and decrypt them when showing back to the users (that's just for privacy reasons). Since I couldn't find any native encrypt/decrypt library or even a better solution, then I am using the "crypto-js" (https://code.google.com/p/crypto-js/), and it's working well so far. The problem is: when the user write a message I encrypt it and save it at the database. But when I retrieve that message from the database using the "find" method in a Template Helper (using the reactive computation idea to approach the desired "Live HTML"), what I get is just a cursor that will be used to render the message in my HTML. As you can see, the message is shown without be decrypted.
I was thinking in "fetch" the data from the cursor, run the decrypt function in a "for loop" over all messages, but that's too inefficient.
I was wondering if someone know how may I manipulate the data from the cursor before it be render, then I'll be able to decrypt each message on the fly.
Really thanks for your attention and sorry any bother.
You could use a transform function. The transform is passed as the cursor is used so it only runs on each document as it is used:
YourCollection.find({}, {transform:function(doc) {
var encrypted = doc.field1;
doc.field1 = decrypt(encrypted)
return doc;
});
So now each field1 would be decrypted (on the web browser). Just before it was used. If you use .fetch() you would get all the decrypted data too.
You didn't posted the related code here, but I assume you have done something like this:
Template.yourTemplate.yourHelper = function(){
return yourCollection.find({});
}
The thing is your are returning the data to the helper, in form of cursor, which is perfectly acceptable in general. But as you are storing encrypted messages in collection, each message is rendered as it is without performing decryption.
So, try to fetch an array instead of cursor using find().fetch() which gives the array equivalent of your cursor. Something like :
Template.yourTemplate.yourHelper = function(){
var msg_arr = yourCollection.find({}).fetch(); // gives array instead of cursor.
msg_arr.forEach( function( msg ){
// traverse through each element of array and
// perform decryption.
});
}
I just had a talk at the #meteor IRC channel and some ideas came out. And I thought that this one is the best solution for my case:
{{#each messages}}
{{decrypt}}
{{/each}}
As helpers get the data from the context, the helper "decrypt" got the actual "message" in the loop as a "this" object. Then, I did the decryption and returned the message in plain text.
It works pretty well, further it is called reactively and make use of the cursor (that is update dynamically if data changes during the exhibition).
Thanks everybody whom helped me.

Asynchronous validation in QWizard

I'm writing a wizard UI based on the QWizard Qt object. There's one particular situation where I want the user to log in to a service using host, username, and password. The rest of the wizard then manipulates this service to do various setup tasks. The login may take a while, especially in error cases where the DNS name takes a long time to resolve -- or perhaps it may not even resolve at all.
So my idea is to make all three fields mandatory using the registerField mechanism, and when the user hits Next, we show a little throbber on the wizard page saying "Connecting to server, please wait..." while we try to connect in the background. If the connection succeeds, we advance to the next page. If not, we highlight the offending field and ask the user to try again.
However, I'm at a loss for how to accomplish this. The options I've thought of:
1) Override validatePage and have it start a thread in the background. Enter a wait inside validatePage() that pumps the Qt event loop until the thread finishes. You'd think this was the ugliest solution, but...
2) Hide the real Next button and add a custom Next button that, when clicked, dispatches my long running function in a thread and waits for a 'validation complete' signal to be raised by something. When that happens, we manually call QWizard::next() (and we completely bypass the real validation logic from validatePage and friends.) This is even uglier, but moves the ugliness to a different level that may make development easier.
Surely there's a better way?
It's not as visually appealing, but you could add a connecting page, and move to that page. If the connection succeeds, call next() on the wizard, and if the connection fails, call previous() and highlight the appropriate fields. It has the advantage of being relatively straightforward to code.
My final choice was #2 (override the Next button, simulate its behavior, but capture its click events manually and do the things I want to with it.) Writing the glue to define the Next button's behavior was minimal, and I was able to subclass QWizardPage with a number of hooks that let me run my task ON the same page, instead of having to switch to an interstitial page and worry about whether to go forwards or backwards. Thanks Caleb for your answer though.
I know this has already been answered (a long time ago!) but in case anyone else is having the same challenge. Another method for this is to create a QLineEdit, initiate it as empty and set it as a mandatory registered field. This will mean that "Next" is not enabled until it is filled with some text.
Run your connection task as normal and when it completes use setText to update the QLineEdit to "True" or "Logged in" or anything other than empty. This will then mean the built in isComplete function will be passed as this previously missing mandatory field is now complete. If you never add it to the layout then it won't be seen and the user won't be able to interact with it.
As an example ...
self.validated_field = QLineEdit("")
self.registerField('validated*', self.validated_field)
and then when your login process completes successfully
self.validated_field.setText("True")
This should do it and is very lightweight. Be sure though that you consider the scenario where a user then goes back to that page and whether you need to reset the field to blank. If that's the case then just add in the initialisePage() function to set it back to blank
self.validated_field.setText("")
Thinking about it you could also add the line edit to the display and disable it so that a user cannot update it and then give it a meaningful completion message to act as a status update...
self.validated_field = QLineEdit("")
self.validated_field.setDisabled(True)
self.validated_field.setStyleSheet("border:0;background-color:none")
self.main_layout.addWidget(self.validated_field)
self.registerField('validated*', self.validated_field)
and then when you update it..
self.validated_field.setText("Logged in")

Resources