I'm trying to create a sublime text plugin. I successfully created it, and I'm now trying to add an item to the menu, and when it's selected, it will call the plugin. I'm having trouble inserting the menu item in the correct place, and calling the plugin once created.
Say I have the following plugin:
import sublime, sublime_plugin
class ExampleCommand(sublime_plugin.TextCommand):
def run(self, edit):
self.view.insert(edit, 0, "Hello, World!")
I created a folder at
C:\Users\"userName"\AppData\Roaming\Sublime Text 3\Packages\"My Plugin"
and added the plugin file to that directory. I then added the following code in a file called Main.sublime-menu
[
{
"id": "file",
"children":
[
{"id": "save"},
{"caption": "My Plugin"},
{ "command": "myPlugin" }
]
}
]
The problem is, I get two My Plugin and myPlugin items in the menu, and it's after the exit menu. I want it to be after save. Also, when I select My Plugin, I get an error in the console:
Unable to parse command:
How can I add a menu item after the save menu item, and have the menu item call a plugin called myPlugin?
Command names in plugins are not taken from the name of the python file that they're stored in; they are derived from the name of the class that implements the command so that multiple commands can be stored in a single file.
Additionally, command names are snake cased and forced to be all lower case. If your class is not named in that style, Sublime will convert it to that style by:
Throwing away the Command text at the end (if it exists)
Convert a leading upper case character to lower case
Replacing every other upper case character with an underscore and that character's lower case equivalent.
This means that for your example above, the command name you would use is example. You can't make it be myPlugin because that has an upper case character in it. Naming the class MyPluginCommand, MyPlugin or my_plugin would create a command named my_plugin, which is as close as you can get.
Your example content for Main.sublime-menu is not following the proper data structure for the items in the children array, which is why the items appear twice. There is some unofficial documentation on the menu format that outlines the fields and structure for menu items.
The reason the items are being appended to the end of the menu is because of how menus from multiple packages are merged together. Basically some items have an id field in them that gives them a unique ID; when multiple items have the same ID, they get concatenated together in the order that the packages that they came from were loaded.
Your menu items use the id of file to indicate the file menu, and then include an id of save; since the default main menu does not contain an item with that id, your items get stuck onto the end of the menu instead.
The error you're seeing in the console is because the menu item with the caption of My Plugin does not contain a command field; instead, the menu item that follows it specifies a command and does not specify a caption. Sublime is telling you that it can't parse the command because it couldn't find one.
In order to do what you want, you want a Main.sublime-menu that looks something like this:
[
{
"id": "file",
"children":
[
{
"caption": "My Plugin",
"command": "my_plugin"
}
]
},
]
This assumes that you have renamed the class implementing the command as outlined above.
Related
I have an old visual prolog project in which I have to change the text of a menu during runtime.
This is what I've done to change the text:
menu_setText(Win, id_menu, NewMenuText)
This works fine, however, when I want to enable/disable this menu, the following does not work (meaning the menu item doesn't change its state):
menu_Enable(Win, id_menu, b_true)
After some search, I found that:
Under MS-Windows, submenus can not be referred to by a resource identifier. If the menu entry for a submenu, needs to enabled, disabled, checked or have the text changed. it is necessary to use a special versions of the menu_Enable, menu_Check and menu_SetText predicates, which specify the text of the menu entry instead of the constant.
menu_Enable(WinHandle, String, BOOLEAN)
menu_Check(WinHandle, String, BOOLEAN)
menu_SetText(WinHandle, String, NewString)
The weird thing is that in my case, menu_setText works just fine with the constant where menu_Enable requires the text itself. (yes I tested menu_Enable with the initial text of the menu item, but when the text changes then everything breaks)
Here comes my question:
How can I enable/disable a menu when I know its ID but not its name ?
If not possible directly, how can I get the current name of a menu when I know its ID ?
In case this helps, this project is opened and compiled with VIP52 (since before the year 2001).
I finally found a workaround that solves my problem, but I'm still not really satisfied, so if anyone comes up with a better answer, I'll take it !
I declared:
txt_menu(menu_tag,string)
And then called:
txt_menu(id_menu, MenuText),
menu_setText(Win, MenuText, NewText),
retractAll(txt_menu(id_menu,_)),
assert(txt_menu(id_menu,NewText)),
menu_Update(Win)
whenever I have to change the text of a menu item, and this can easily be transformed into a menu_setTextById predicate as such:
menu_setTextById(Win, MenuId, NewText):-
txt_menu(MenuId, MenuText),
menu_setText(Win, MenuText, NewText),
retractAll(txt_menu(MenuId,_)),
assert(txt_menu(MenuId, NewText)),
menu_Update(Win).
with the usage:
menu_setTextById(Win, id_menu, "My new text menu").
Noted that if I ever have the need to have several windows with menus, I'll have to add the Window Id to my txt_menu clause.
The main problem with this workaround is that I can't use & in the new text menu because if my menu has "&Menu" as text (meaning that M will be underlined), then trying to use menu_setText(Win,"&Menu","New Menu") will break because "&Menu" is not found.
So I'd need to remove any ampersand from the string before trying to use it in such predicates.
I have written an Orchard Module and would like an item to appear in a Navigation list when the module is Enabled. Ideally, I would like to be able to remove the item when the Module is disabled.
Where should I hook into to for when the module is enabled and disabled?
How do I programmatically add a menu item to an already existing Navigation?
You can implement the IMenuProvider interface for this. An example implementation might look something like this:
namespace Orchard.Bar {
public class SuperMenuProvider : IMenuProvider {
private readonly IOrchardServices _orchardServices;
public SuperMenuProvider(IOrchardServices orchardServices) {
_orchardServices = orchardServices;
T = NullLocalizer.Instance;
}
public Localizer T { get; set; }
public void GetMenu(IContent menu, NavigationBuilder builder) {
string position = "10";
builder.Add(T("Foo"), position, item => item.Url("http://foo.com").AddClass("someClass"));
builder.Add(T("Bar"), position + ".1", item => item.Action("Index", "Foo", new { area = "Orchard.Bar" }));
if (_orchardServices.Authorizer.Authorize(Orchard.Security.StandardPermissions.AccessAdminPanel)) {
builder.Add(T("Secure FooBar"), position + ".2", item => item.Action("Index", "Secure", new { area = "Orchard.Bar" }));
}
}
}
}
This will appear on all menus on the front end. You may want to put in the name of the menu you are targeting if you know for sure that is what it is called (default in Orchard is "Main Menu", people don't generally change it to be honest). This could be a little brittle, so you may want it customizable, either with a site setting or you could create a part that you attach to the menu content type that lets the admin specify whether to show your menu items on the said menu.
An alternative approach would be to hook into the modules enable event using IFeatureEventHandler and using the content manager to create menu items with urls and adding them to a specified Menu. I don't really recommend this approach; you lose control of the menu items (e.g. to update a url), they can be removed from the menu accidentally, you have to know the name of the Menu you are adding them to, you are more limited (cant do permissions checks etc.).
I assume you are talking about showing up on the front end. If you talking about the admin menu then check out pretty much any module for a file generally called AdminMenu.cs, plenty of examples :)
The question doesn't specify what the module does so I guess we're to assume that it creates a content type. In that case you have (at least) two options:
In the Content Type's Content Definition go to Add Parts and add the Menu part. This will allow you to add a content item to a menu from the item's content editor.
From the Navigation menu choose the appropriate Menu and select add a Content Menu Item. Note that the content type must be set as "listable" in Content Definition in order for the items to be listed as a choice.
Disabling the module should remove the item from the navigation in either case.
I have a search screen which shows results from a 'projects' entity. One of the fields is a link to a 'Clients' entity, which has a client name.
I can use the search box above the data to search by project name, date, etc but I cannot search by client name. i guess because it is actually a reference to a seperate entity.
How can i make it so that I can search for projects, using the search box, by client name?
To try to explain clearer here is the database layout.
Project
------
ProjName
ProjType
ProjComment
Client --------------- Client
-----
Name
Address
I can search by the project fields, but not the client name.
Create a custom query for Project entity and add optional parameters for all the Project and Client properties that you wish to search for. Wire up the custom query filter.
For full control do not wire up the custom query filter, instead filter in code behind, the PreProcess event.
if your using the HTML Client it can be done as follows on a browse screen associated with in your case the Project Table. if you look at the left navigation bar, click on edit query and within here, you can see 3 options, Filter, Sort and Parameters.
Filter should say Client.Name based on your table structure, the second should be changed to "contains", the 3rd should be set as parameter and finally the 4th box is where you create the new parameter you are going to use as a search box...
you can rename the Parameter at the bottom and I always find its best when on this, to set it as optional in the bottom right property box. (This means all the data will be displayed rather than nothing until searched)
Now if you were to go back to your main screen page, drag this parameter from the left onto the main screen page and set it as a text box. Using this and pressing enter after you have typed something will display the results that match what you have typed so far.
a little more to the above, if you were to click "Edit PostRender Code" and add the below then after 3 characters are entered, the table list your searching through will be updated automatically after each finger stroke...
$searchBox = $("input", $(element));
setTimeout(function () {
$searchBox.focus();
}, 1);
onInputAsYouType(element, 1, function (text) {
contentItem.screen.[CREATED PARAM NAME] = text; //SearchText here is the data item in the screen designer linked to the query parameter
});
function onInputAsYouType(element, numberOfRequiredChars, done) {
var inputbox = $("input", $(element));
inputbox.on("input", function (e) {
var text = $(this).val();
if (text.length >= numberOfRequiredChars)
done(text);
});
};
};
I know that sublime text categorizes the source code into different scopes. Especially used for syntax highlighting.
(You can display the current scope with Ctrl+Alt+Shift P or diverse plugins)
But can you also search for/within one scope ?
Unfortunately there is no functionality built in to ST2 or ST3 that allows searches to be confined to a particular scope. If you know Python, a plugin shouldn't be too hard to write using the functions sublime.View.find() and sublime.View.find_all(), filtering the results through sublime.View.scope_name(), although you'd need to collapse the Region returned by find() to a single point for passing to scope_name().
If you're not the plugin-writing type, you might want to check out the ScopeHunter and/or ScopeAlways plugins, available through Package Control. I bind the ScopeHunter functionality to a key combination that pops up a panel with the current scope:
[
// ScopeHunter
{ "keys": ["ctrl+alt+shift+s"], "command": "get_selection_scope" }
]
A slightly less keyboard-intensive method would be to use ScopeAlways, which displays the current scope in the status bar:
This way you can move through your Find results and immediately see what scope(s) they belong to. To set it up, once you've installed the plugin from Package Control, open Preferences -> Package Settings -> ScopeAlways -> Settings - User and add the following to have it start when Sublime starts:
{
"start_on": true
}
Save the file, restart Sublime, and enjoy all the scope goodness.
I am trying to work with mouseover on a particular Item in my application by using the following command
{
ie.text_field(:xpath, "//a[contains(text(),'Deal')]").fire_event('onmouseover')
}
On doing mouseover on a item, two subitems are displayed.
Is there any way to capture the sub items which are part of the Item by doing mouseover with which we can report that our test is pass or fail.
Please suggest.
Additional Information :
If we take example,On the StackOver flow page, If i do mouseover on my name, i get a window where i see activity, privileges, Logout and other stuff. This is really what i was looking for. Is there a way to capture the items displayed on the window on doing mouseover.
I also tried to capture the subitems with the following :
{
text=ie.text_field(:xpath, "//a[contains(text(),'Deal')]").fire_event('onmouseover')
puts(text.inspect)
}
On doing this "text" value is displayed as 'nil'.
My general tactic for such things is a combination of using IRB and the IE Developer tool, or Firebug.
using IRB, type out (or cut and paste) the watir statement to fire the onmouseover command to the proper element on the page.
Then have the developer tool rescan the DOM (there's a little refresh icon you can click) The use the tool to point to an element to point to one of the items in the stuff exposed by the onmouseover. Using the info from that, you can then figure out how to address those elements to get the text from the proper div, etc.
If I do that here to the info that opens up when I float the mouse over my name I can find out that it is a table of class "profile-recent-summary" Furthermore I can then look at the way the table is made up and see for example that the 'today' reputation value is in the second cell on that row.. The row also has the text 'reputation' in it.. so
browser.table(:class, 'profile-recent-summary').row(:text, /reputation/).cell(:index, 2).flash
Should flash the cell I want (index might be 1 if using firewatir or webdriver) I can then replace the .flash with something else like .text if I want to get the text from that cell (which is actually inside a link that sits in the cell)..
without seeing your code, I would 'inspect' the element that you are trying to verify and when_present (text) assert that its true