|
| 1 | +// Adds an editor tab context menuitem for opening a komodo file in |
| 2 | +// an alternative location. The alternative locations are read from the |
| 3 | +// "locations.ini" file in the Komodo profile directory. |
| 4 | +// |
| 5 | +// Example "locations.ini" config file: |
| 6 | +// |
| 7 | +// path1 = /home/toddw/src/checkout1/ |
| 8 | +// path2 = /home/toddw/alt/checkout2/ |
| 9 | +// |
| 10 | +// Given the above configuration, if I had this file open in Komodo: |
| 11 | +// /home/toddw/src/checkout1/libs/entry1.py |
| 12 | +// I could right click on the tab, choose "Open at location > path2", |
| 13 | +// and Komodo would try to open this file: |
| 14 | +// /home/toddw/alt/checkout2/libs/entry1.py |
| 15 | +// |
| 16 | + |
| 17 | +if (typeof(window.extensions) == 'undefined') { |
| 18 | + window.extensions = {}; |
| 19 | +} |
| 20 | +if (typeof(extensions.locations) == 'undefined') { |
| 21 | + extensions.locations = {}; |
| 22 | +} |
| 23 | + |
| 24 | +extensions.locations.paths = []; |
| 25 | + |
| 26 | +extensions.locations.editConfigFile = function() { |
| 27 | + var koDirs = Components.classes["@activestate.com/koDirs;1"].getService(Components.interfaces.koIDirs); |
| 28 | + var koOs = Components.classes["@activestate.com/koOs;1"].getService(Components.interfaces.koIOs); |
| 29 | + var configpath = [koDirs.userDataDir, "locations.ini"].join(koOs.sep); |
| 30 | + ko.open.URI(configpath); |
| 31 | +} |
| 32 | + |
| 33 | +extensions.locations.openAtIndex = function(idx) { |
| 34 | + var view = ko.views.manager.currentView; |
| 35 | + var file = view.koDoc.file; |
| 36 | + var fpath = file.path; |
| 37 | + // Find out what configuration it's coming from. |
| 38 | + var prefix = ""; |
| 39 | + for (var i=0; i < extensions.locations.paths.length; i++) { |
| 40 | + var trypath = extensions.locations.paths[i]; |
| 41 | + // Prefer the longest config path. |
| 42 | + if (fpath.startsWith(trypath) && prefix.length < trypath.length) { |
| 43 | + prefix = trypath; |
| 44 | + break; |
| 45 | + } |
| 46 | + } |
| 47 | + if (!prefix) { |
| 48 | + ko.dialogs.alert("This file is not a descendant of any directory in the config file"); |
| 49 | + return; |
| 50 | + } |
| 51 | + // Open at the alternative location. |
| 52 | + var scimoz = view.scimoz; |
| 53 | + var lineno = scimoz.lineFromPosition(scimoz.currentPos) + 1; |
| 54 | + var osPathSvc = Components.classes["@activestate.com/koOsPath;1"].getService(Components.interfaces.koIOsPath); |
| 55 | + var path = extensions.locations.paths[idx]; |
| 56 | + var rel_path = fpath.substr(prefix.length); |
| 57 | + var path = osPathSvc.join(path, rel_path); |
| 58 | + ko.views.manager.doFileOpenAtLineAsync(path, lineno); |
| 59 | +} |
| 60 | + |
| 61 | +// Creating the UI. |
| 62 | +function createXULElement(tagName, attributes) { |
| 63 | + var elem = document.createElement(tagName); |
| 64 | + var attr; |
| 65 | + for (attr in attributes) { |
| 66 | + elem.setAttribute(attr, attributes[attr]); |
| 67 | + } |
| 68 | + return elem; |
| 69 | +} |
| 70 | + |
| 71 | +extensions.locations.reloadConfiguration = function() { |
| 72 | + var koDirs = Components.classes["@activestate.com/koDirs;1"].getService(Components.interfaces.koIDirs); |
| 73 | + var koOs = Components.classes["@activestate.com/koOs;1"].getService(Components.interfaces.koIOs); |
| 74 | + var configpath = [koDirs.userDataDir, "locations.ini"].join(koOs.sep); |
| 75 | + |
| 76 | + var menupopup = document.getElementById("openKomodoLocationMenupopup"); |
| 77 | + if (!menupopup) { |
| 78 | + // Create the menu. |
| 79 | + var menu = createXULElement("menu", { |
| 80 | + "id": "openKomodoLocationMenu", |
| 81 | + "label": "Open at location" |
| 82 | + }); |
| 83 | + var menupopup = createXULElement("menupopup", { |
| 84 | + "id": "openKomodoLocationMenupopup" |
| 85 | + }); |
| 86 | + menu.appendChild(menupopup); |
| 87 | + var tabContextMenu = document.getElementById("tabContextMenu"); |
| 88 | + tabContextMenu.insertBefore(menu, document.getElementById("menu_splittab")); |
| 89 | + } else { |
| 90 | + // Remove all existing openAt menu entries. |
| 91 | + while (menupopup.firstChild) { |
| 92 | + menupopup.removeChild(menupopup.firstChild); |
| 93 | + } |
| 94 | + } |
| 95 | + |
| 96 | + // Load the config file and read all the entries. |
| 97 | + var kofile = Components.classes["@activestate.com/koFileEx;1"].createInstance(Components.interfaces.koIFileEx); |
| 98 | + kofile.URI = ko.uriparse.pathToURI(configpath); |
| 99 | + if (!koOs.path.exists(configpath)) { |
| 100 | + // Create a template one. |
| 101 | + var template = "# Kobranch configuration file\n" + |
| 102 | + "#\n" + |
| 103 | + "# Format of entries is: <name> = <path>\n" + |
| 104 | + "#\n" + |
| 105 | + "# Examples:\n" + |
| 106 | + "# foo = /home/toddw/src/branch2/src\n" + |
| 107 | + "# zoink = C:\path\to\code\directory\n" + |
| 108 | + "#\n" + |
| 109 | + ""; |
| 110 | + kofile.open("w"); |
| 111 | + kofile.puts(template); |
| 112 | + kofile.close(); |
| 113 | + } |
| 114 | + kofile.open("r"); |
| 115 | + var contents = kofile.readfile(); |
| 116 | + kofile.close(); |
| 117 | + // Parse the entries: "name = /absolute/path/to/dir" |
| 118 | + var lines = contents.split("\n"); |
| 119 | + var match; |
| 120 | + var menuitem = null; |
| 121 | + for (var i=0; i < lines.length; i++) { |
| 122 | + match = lines[i].match(/^(.*?)\s*=\s*(.*)$/); |
| 123 | + if (match && match[1][0] != "#") { |
| 124 | + var branchdir = koOs.path.expanduser(match[2]); |
| 125 | + // Add directory separator on the end. |
| 126 | + if (!branchdir.substr(-1) != koOs.sep) { |
| 127 | + branchdir += koOs.sep; |
| 128 | + } |
| 129 | + if (extensions.locations.paths.indexOf(branchdir) >= 0) { |
| 130 | + continue; // That path already exists. |
| 131 | + } |
| 132 | + menuitem = createXULElement("menuitem", { |
| 133 | + "id": "openKomodoLocationMenuitem_" + match[1], |
| 134 | + "label": match[1], |
| 135 | + "oncommand": "extensions.locations.openAtIndex(" + extensions.locations.paths.length + ")" |
| 136 | + }); |
| 137 | + menupopup.appendChild(menuitem); |
| 138 | + extensions.locations.paths.push(branchdir); |
| 139 | + } |
| 140 | + } |
| 141 | + if (menuitem) { |
| 142 | + // Items for found - add a separator. |
| 143 | + menupopup.appendChild(createXULElement("menuseparator")); |
| 144 | + } |
| 145 | + // Create menuitem to access the config file. |
| 146 | + menuitem = createXULElement("menuitem", { |
| 147 | + "id": "openKomodoLocationMenuitem_editfile", |
| 148 | + "label": "Edit configuration file", |
| 149 | + "oncommand": "extensions.locations.editConfigFile()" |
| 150 | + }); |
| 151 | + menupopup.appendChild(menuitem); |
| 152 | + // Create config reload menuitem. |
| 153 | + menuitem = createXULElement("menuitem", { |
| 154 | + "id": "openKomodoLocationMenuitem_editfile", |
| 155 | + "label": "Reload configuration", |
| 156 | + "oncommand": "extensions.locations.reloadConfiguration()" |
| 157 | + }); |
| 158 | + menupopup.appendChild(menuitem); |
| 159 | +} |
| 160 | + |
| 161 | +// Load for the first time. |
| 162 | +extensions.locations.reloadConfiguration(); |
0 commit comments