Visual Studio SDK - How to add a margin glyph on command invoked? - visual-studio-extensions

How can I modify this sample: https://msdn.microsoft.com/en-us/library/ee361745.aspx to have glyphs added to the margin when a button I added is clicked?
I have a button which creates a special kind of breakpoint. I would like this kind to be recognized by my own margin glyph. So I wrote the GetTags method in my Tagger class as follows:
IEnumerable<ITagSpan<MyBreakpointTag>> ITagger<MyBreakpointTag>.GetTags(NormalizedSnapshotSpanCollection spans)
{
if (BreakpointManager != null)
{
DTE2 ide = ServiceProvider.GlobalProvider.GetService(typeof(DTE)) as DTE2;
Document document = ide.ActiveDocument;
foreach (SnapshotSpan span in spans)
{
ITextSnapshot textSnapshot = span.Snapshot;
foreach (ITextSnapshotLine textSnapshotLine in textSnapshot.Lines)
{
if (BreakpointManager.IsMyBreakpointAt(document.FullName, textSnapshotLine.LineNumber + 1))
{
yield return new TagSpan<MyBreakpointTag>(new SnapshotSpan(textSnapshotLine.Start, 1),
new MyBreakpointTag());
}
}
}
}
}
However, glyphs are added after moving the cursor to a different line of code or making changes to the code. What do I have to do to have glyphs added right after the button is clicked?

GetTags is called by the editor whenever a layout happens, but the editor won't call it for any random reason. (Think: how would it know when to call you?) You need to raise the TagsChanged event from your tagger to say the tags for a given span changed, and then it'll call GetTags again to refresh.
As an unrelated piece of advice: you shouldn't be using DTE.ActiveDocument in your GetTags for a few reasons:
GetTags should be as fast as possible...calling DTE methods are rarely fast.
Imagine you have two files open, and GetTags is called for the non-active file. That would have both files looking at the same filename which is probably bad. There's code here that shows how to fetch the file name from an ITextBuffer.

This is copied from my answer here. Basically, changing from using ITaggerProvider to IViewTaggerProvider allowed me to redraw the glyphs. I used the Implementing a Brace Matching Tagger Provider section in Walkthrough: Displaying Matching Braces example to make these changes.
Using the IViewTaggerProvider, you can then call
TagsChanged?.Invoke(this, new SnapshotSpanEventArgs(
new SnapshotSpan(
SourceBuffer.CurrentSnapshot,
0,
SourceBuffer.CurrentSnapshot.Length)));
in your functions to explicitly call GetTags and go over the spans in the current snapshot.

Related

Changing the History Stack Size in adobe brackets

I have not been able to find a way to increase the size of the undo stack, or even better, make it persistent across different sessions.
I have looked through the extensions and there does not appear to be one available, is this because it is already available and I am unable to find it?
The way you do this in regular CodeMirror is:
cm.setOption("undoDepth", 200);
(200 is actually the default, fyi)
Brackets wraps CodeMirror objects in an object called Editor. There's no way to directly monitor when Editor objects are created, but you can do something like this:
$(EditorManager).on("activeEditorChange", function (event, editor) {
if (!editor._myExtension_historyAdjusted) {
editor._myExtension_historyAdjusted = true;
editor._codeMirror.setOption("undoDepth", 400);
}
});

How to handle first tab size on formatting?

I create an extension, that format vs editor tabs in custom ways, using ITextParagraphPropertiesFactoryService class. Everything works just fine, expect the fact, that when user enter new line, ITextParagraphPropertiesFactoryService doesnt affect to the new line
For simplifying the problem, I create a new MEF project, add a format provider like this
[Export(typeof(ITextParagraphPropertiesFactoryService))]
[ContentType("text")]
[TextViewRole(PredefinedTextViewRoles.Document)]
internal class ElasticTabstopsProvider : ITextParagraphPropertiesFactoryService
{
/// <summary>
/// Creates an ElasticTabstopsFormatters for
/// the provided configuration.
/// </summary>
public TextParagraphProperties Create(IFormattedLineSource formattedLineSource, TextFormattingRunProperties textProperties,
IMappingSpan line, IMappingPoint lineStart, int lineSegment)
{
return new TextFormattingParagraphProperties(textProperties, 1);
}
}
And it changes all tabs width from my editor to 1. Great! This is what I want. But now when I press Enter(new line) new cursor is set under Main, however I expect tab widths to be 1.
After I start typing it goes to expected position.
The question is, how can I set new line empty line tab size?
I try to override ISmartIndentProvider, but seems vs ignore that value.
Debuger stops on breakpoint in method
int? GetDesiredIndentation(ITextSnapshotLine currentLine)
of ISmartIndent, but indent stays the same no matter what value I return...
There are at least two reasons why your ISmartIndentProvider's indent is being ignored:
First, there are lots of places with the current C# and VB language services where we explicitly set the caret position in response to certain keypresses. Enter is one of them. It's quite possible that in your scenario, we're explicitly setting the position. Short of disabling smart indenting in Tools > Options, there's nothing you can do to override that. Since you said you're getting a debugger hit in your ISmartIndentProvider, that's probably the issue here.
Second, if you're trying to define a ISmartIndentProvider for content type "text", yours won't get called if there is a language-specific provider. There's also another provider for "text" already (which calls the shimmed old language services) which might win over yours anyways.
To be honest, if you're trying to do something fancy where you don't want automatic indenting, then you really should just turn it off to ensure it's not getting in your way.

How to add default custom action to dashlet's title bar in Alfresco Share

Since some days ago I'm struggling to find out the best way to add a custom action in every dashlet's title bar by default.
At this stage, I know the actions are set up as a widget in every dashlet's webscript. For example, in docsummary.get.js:
var dashletTitleBarActions = {
id : "DashletTitleBarActions",
name : "Alfresco.widget.DashletTitleBarActions",
useMessages : false,
options : {
actions: [
{
cssClass: "help",
bubbleOnClick:
{
message: msg.get("dashlet.help")
},
tooltip: msg.get("dashlet.help.tooltip")
}
]
}
};
model.widgets = [docSummary, dashletResizer, dashletTitleBarActions];
Then, the widget is instanciated in when the page is rendered.
I have figured out the next approaches:
Augment the "actions" array of every widget instance with the action I need in a custom JS snippet, every time the page is rendered. I have performed some tests without success using techniques like this: http://acidmartin.wordpress.com/2012/03/19/getting-instance-names-of-a-javascript-object/
Modify the prototype of Alfresco.widget.DashletTitleBarActions by adding my custom action. I believe it doesn't work either as the "actions" object is always overridden when the widget is instantiated, as you can see in the code above pasted.
Create an extension module for every dashlet's webscript which adds the custom action for every Alfresco.widget.DashletTitleBarActions widget definition, similarly as Dave Drapper explains in his post http://blogs.alfresco.com/wp/ddraper/2012/05/22/customizing-share-javascript-widget-instantiation-part-1/
Get every dashlet div container and add the action required directly manipulating the DOM once the page is ready. It should work but is something I consider slightly dirty and inconsistent, hence I would like to avoid it.
Could anyone imagine a better and feasible solution??
Let's start with adding an action to a single existing dashlet. As you suggest in (3) you can define an extensibility module to change the behaviour of the dashlet by intercepting and modifying its model.
Creating an extensibility module is well covered on the blog article and follow-up posts, but the trick here is to provide a controller JavaScript extension which locates the DashletTitleBarActions widget and adds your action to it, e.g.
if (model.widgets)
{
for (var i = 0; i < model.widgets.length; i++)
{
var widget = model.widgets[i];
if (widget.id == "DashletTitleBarActions")
{
widget.actions.push({...})
}
}
}
What you put in the object literal depends on how your action is implemented. If you require some client-side behaviour (rather than say, a static link) then you will also need to bind that in using a CustomEvent - see the RSS Feed dashlet org/alfresco/components/dashlets/rssfeed.get.html.ftl for an example.
The down-side of an extensibility module is that you will need to define an explicit extension JS file for each dashlet. You could easily put the code above in a central file and then include it in each dashlet extension where it is needed, e.g.
<import resource="classpath:alfresco/site-webscripts/org/myco/utils/dashlet.utils.js">
I would take the road number 2 here.
The definition of this widget is in share.js file ({share.context}/js/share.js). For Alfresco 4.2, DashletTitleBarActions is defined at around line 1700. In the onReady handler of the widget, there's a loop that processes the actions.
// Reverse the order of the arrays so that the first entry is furthest to the left...
this.options.actions.reverse();
// Iterate through the array of actions creating a node for each one...
for (var i = 0; i < this.options.actions.length; i++)
{
As you can see, it reverses the order of actions parameter, and then adds starts to loop the actions. So depending if you want your action to be the first or last, you could probably edit this file and add your custom action:
myAction = {
"cssClass": "customCSS"
, "tooltip": this.msg("slingshot.messages.generic.tooltip")
, "eventOnClick": ...
...
}
this.options.actions.push(myAction);
// now move on with the rest of the loop
for (...)
Of course, that requires overwriting shares' own js file, and not extending it. If you can't do that, you would then have to include a custom JS file on each page where share.js is also included and make sure it's executed after share.js but before any of the widgets are ready, and overwrite the onReady method of the widget itself so that it does this.

Why can't I move a field into a fieldset in a Drupal form - fails to pick up current value

I have a node form in Drupal 7, in order to simplify it for the user I want to break it up into sections using the vertical tabs feature.
Using hook_form_FORMID_alter() I can move the fields without difficulty. When the node is saved, it writes the values correctly, and they appear in the node view.
But when I re-edit the node any value for a moved field is not set so I effectively lose the data. I've tried various options including changing the array_parents value in form_state['fields'][field][langcode].
(I wondered whether it would be better to move the fields during pre_render instead.)
Any ideas?
Field API fields by default are placed into a container field type. If you want to convert them to a fieldset in the vertical tabs, you can do the following:
$form['field_tags']['#type'] = 'fieldset';
$form['field_tags']['#title'] = 'Tags';
$form['field_tags']['#group'] = 'additional_settings';
A better solution would be to use the new Field Group module so you can make these modifications through the UI, rather than in code.
Sometimes it works better to move field items around in the #after_build step of the form creation process.
in hook_form_alter, you set your after build function like so:
function mymodule_form_alter(&$form, &$form_state, $form_id)
{
$form['#after_build'][] = 'mymodule_myform_after_build';
}
Then you define your after_build function like so:
function mymodule_myform_after_build($form)
{
//do stuff to the form array
return $form;
}
I think you can even define after_build on individual elements.
Anyway, it's a good way to alter the form after all the modules have done their thing.

Implementing Finite State Machine for Web UI

I am intending to develop a Finite State Machine in the following manner.
Extract Control IDs from a --> web-page,
Write control IDs to a XML --> Controls-XML.
Manually declare States and Transition in the --> Controls-XML
Scan Controls-XML and attach pre-declared Jscript to eventhandlers embed them in the --> web-page..
5.
How feasible this would be..
Am I getting into can of worms ?
First, we live in a can of worms!
your questions are a bit vague, please provide more details if i'm missing your point and maybe this should be beak in parfts to deepen the discution in part details
assuming you want to work live on a client side browser over any page
by extrating ID's of controls i supouse it's all controls of a webpage (it could be by clicking or clicking possibly with key combos), but lets be simple.
Extrating ID's
here's a code than might help you:
function scan(e) {
if (e&&e.childNodes)
for(var i=0;i<e.childNodes.length;i++) {
var child=e.childNodes[i];
if (child) {
if(child.id) console.log(child.nodeName,child.id);
scan(child);
}
}
}
note: this was done with chrome, but any browser console will do i think.
just paste the function on the console and then call it like:
scan(document)
and it will list (on console) all elements that have id's showing element type and id... you can filter that eazy by just printing elements of certain tags like INPUT, SELECT TEXTAREA, etc...
About the XML
here browsers get a bit tricky, you can simplify it too your favorite browser, the following functions constructs a XML document given some XML text.
So by this aproach your scan function should compose the xml text (instead of writing to the console) and later we can feed the XML document
function makeNode(text) {
var doc;
if (window.ActiveXObject) {
doc=new ActiveXObject("Microsoft.XMLDOM");
doc.async="false";
doc.loadXML(text);
} else {// code for Mozilla, Firefox, Opera, etc.
var parser=new DOMParser();
doc=parser.parseFromString(text,"text/xml");
}// documentElement always represents the root node
return doc.documentElement;
}
other aproach is to create an empty XML document (as the above function does) and the instead of feed raw xml text your scan function should use XMLDOM commands to insert nodes into the document.
Manually declare States and Transition in the --> Controls-XML
this is an hard one, is this (XML doc) info to be copy/pasted and latter edited? is it edited inplace by inserting a bunch of code to build an interface?
many doubts here, but once we have the information in XML format we would be free to use our imagination and decide a format to handle the wanted state changes.
Scan Controls-XML and attach pre-declared Jscript to eventhandlers embed them in the --> web-page
at this point actions depend on methods followed above, but in any case using XMLDOM functions to traverse the xml doc and apply status change or event handlers to the controls is trivial.
controls need not be scanned anymore because we have stored the id's (use getElementById)
i have a form validation system that does something similar, except the XML is predefined and stored on server side, but once loaded it will do just that. attaching event handlers and do status changes based on evaluated expressions.

Resources