Skip to content

Commit

Permalink
support multiple javascript package manager
Browse files Browse the repository at this point in the history
  • Loading branch information
fcannizzaro committed Jun 29, 2017
1 parent 6e098b8 commit 5281546
Show file tree
Hide file tree
Showing 2 changed files with 121 additions and 96 deletions.
9 changes: 5 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,8 @@ auto install npm modules, show npm icons, autocomplete require, open npmjs docum

## Settings

| key | default | action |
|-----------------------|:-------------:|-----------------------------------------------|
| `npm_install_on_save` | **true** | auto-install node modules **on save**. |
| `npm_autocomplete` | **true** | autocomplete node modules's require. |
| key | default | action |
|-----------------------|:-------------:|---------------------------------------------------|
| `npm_install_on_save` | **true** | auto-install node modules **on save**. |
| `npm_autocomplete` | **true** | autocomplete node modules's require. |
| `npm_manager` | **"npm"** | javascript package manager: `npm`, `yarn`, `pnpm` |
208 changes: 116 additions & 92 deletions npm-install.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,66 +8,78 @@
from os import listdir, path
from sublime import Region

CORE = [
'assert', 'buffer', 'child_process', 'cluster', 'crypto', 'dgram',
'dns', 'domain', 'events', 'fs', 'http', 'https', 'net', 'os', 'path',
'punycode', 'querystring', 'readline', 'stream', 'string_decoder', 'tls',
'tty', 'url', 'util', 'v8', 'vm', 'zlib'
]

MODULE = r'.*require\(["\']([^.][^\.]*?)["\']\).*'
ICON = "Packages/npm-install/icon-%s.png"
data = {}
root = {}


def is_valid(view):
return view.file_name() != None and view.file_name().endswith('.js')

def npmls(file, p):
if file not in root:
out = subprocess.check_output(['npm', 'root'], cwd=p, shell=True)
out = out.decode().strip()
root[file] = out
try:
return listdir(root[file])
except Exception:
return []
return view.file_name() != None and view.file_name().endswith('.js')


def node_modules_ls(file, p):
if file not in root:
out = subprocess.check_output(['npm', 'root'], cwd=p, shell=True)
out = out.decode().strip()
root[file] = out
try:
return listdir(root[file])
except Exception:
return []


def cwd(view):
project = re.match(r'(.*)[\/\\].*', view.file_name())
return project.group(1)
project = re.match(r'(.*)[\/\\].*', view.file_name())
return project.group(1)


def update_icons(view):

file = view.file_name()

modules = []
installed = []
installed = []
other = []
result = []
if file not in data:
view.run_command('npm_install', {'action':'initial'})

if file not in data:
view.run_command('npm_install', {'action': 'initial'})
else:
modules = data[file]
modules = data[file]

for region in view.find_all(MODULE):
m = re.search(MODULE, view.substr(region))
a,b = m.span(1)
module = m.group(1)
reg = Region(a + region.begin(), b + region.begin())
if module in modules:
installed.append(reg)
else:
other.append(reg)
result.append(module)
m = re.search(MODULE, view.substr(region))
a, b = m.span(1)
module = m.group(1)
reg = Region(a + region.begin(), b + region.begin())
if module in modules:
installed.append(reg)
else:
other.append(reg)
result.append(module)

flags = sublime.HIDE_ON_MINIMAP | sublime.DRAW_NO_FILL | sublime.DRAW_NO_OUTLINE | sublime.DRAW_SOLID_UNDERLINE
view.add_regions('require-on', installed, 'request', ICON % 'on', flags)
view.add_regions('require-on', installed, 'request', ICON % 'on', flags)
view.add_regions('require-off', other, 'request', ICON % 'off', flags)

return result


def line(view):
sel = view.sel()[0]
line = view.full_line(sel)
req = view.substr(line)
match = re.match(MODULE, req)
return (line, match.group(1) if match else None)
sel = view.sel()[0]
line = view.full_line(sel)
req = view.substr(line)
match = re.match(MODULE, req)
return (line, match.group(1) if match else None)


class NpmExec(threading.Thread):

Expand All @@ -76,23 +88,31 @@ def __init__(self, module, root, action, view):
self.root = root
self.action = action
self.view = view
self.mng = view.settings().get('npm_manager', 'npm')
if self.mng == 'yarn':
self.action = 'add' if action == 'install' else 'remove'
threading.Thread.__init__(self)

def run(self):
self.view.window().status_message('%sing %s' % (self.action, self.module))
subprocess.Popen(['npm', self.action, self.module, '-s'], shell=True, cwd=self.root).wait()
self.view.run_command('npm_install', {'action':'initial'})

def run(self):
if self.module not in CORE:
args = [self.mng, self.action, self.module, '-s']
self.view.window().status_message('%sing %s' % (self.action, self.module))
subprocess.Popen(args, shell=True, cwd=self.root).wait()
self.view.run_command('npm_install', {'action': 'initial'})


class NpmDocCommand(sublime_plugin.TextCommand):

def is_visible(self):
region, module = line(self.view)
return not not module

def run(self, edit):
region, module = line(self.view)
if module: webbrowser.open('https://www.npmjs.com/package/' + module)


def is_visible(self):
region, module = line(self.view)
return not not module

def run(self, edit):
region, module = line(self.view)
if module:
webbrowser.open('https://www.npmjs.com/package/' + module)


class NpmCommand(threading.Thread):

def __init__(self, view, edit, action):
Expand All @@ -103,68 +123,72 @@ def __init__(self, view, edit, action):

def run(self):

if self.action in ['install', 'initial']:
root = cwd(self.view)
file = self.view.file_name()
data[file] = npmls(file, root)
if self.action in ['install', 'initial']:
root = cwd(self.view)
file = self.view.file_name()
data[file] = node_modules_ls(file, root)

install = update_icons(self.view)

if self.action is 'install':
for module in install:
NpmExec(module, root, 'install', self.view).start()

install = update_icons(self.view)

if self.action is 'install':
for module in install:
NpmExec(module, root, 'install', self.view).start()

class NpmInstallCommand(sublime_plugin.TextCommand):

def is_visible(self):
return is_valid(self.view)
return is_valid(self.view)

def run(self, edit, action='install'):
if is_valid(self.view):
NpmCommand(self.view, edit, action).start()
if is_valid(self.view):
NpmCommand(self.view, edit, action).start()


class NpmUninstallCommand(sublime_plugin.TextCommand):

def is_visible(self):
region, module = line(self.view)
return not not module
region, module = line(self.view)
return not not module

def run(self, edit):
if is_valid(self.view):
region, module = line(self.view)
reply = sublime.yes_no_cancel_dialog('Remove "%s" module?' % module, 'Yes', 'No')
if reply == 1:
self.view.erase(edit, region)
NpmExec(module, cwd(self.view), 'uninstall', self.view).start()
if is_valid(self.view):
region, module = line(self.view)
reply = sublime.yes_no_cancel_dialog('Remove "%s" module?' % module, 'Yes', 'No')
if reply == 1:
self.view.erase(edit, region)
NpmExec(module, cwd(self.view), 'uninstall', self.view).start()


def initial(view):
view.run_command('npm_install', {'action':'initial'})
view.run_command('npm_install', {'action': 'initial'})


class EventEditor(sublime_plugin.EventListener):

def on_modified(self, view):
view.run_command('npm_install', {'action':'mark'})

def on_load(self, view):
initial(view)
def on_modified(self, view):
view.run_command('npm_install', {'action': 'mark'})

def on_post_save(self, view):
if view.settings().get('npm_install_on_save', True):
view.run_command('npm_install')
def on_load(self, view):
initial(view)

def get_module(self, module):
clean = module.replace('-', '_').replace('@', '')
return [ module+'\tnpm' , 'var %s = require(\'%s\');\n' % (clean, module) ]
def on_post_save(self, view):
if view.settings().get('npm_install_on_save', True):
view.run_command('npm_install')

def on_query_completions(self, view, prefix, locations):
if is_valid(view) and view.settings().get('npm_autocomplete', True):
file = view.file_name()
if file in data:
return [ self.get_module(module) for module in data[file] if '.' not in module]
return []
def get_module(self, module):
clean = module.replace('-', '_').replace('@', '')
return [module+'\tnpm', 'var %s = require(\'%s\');\n' % (clean, module)]

def plugin_loaded():
for win in sublime.windows():
for view in win.views():
initial(view)
def on_query_completions(self, view, prefix, locations):
if is_valid(view) and view.settings().get('npm_autocomplete', True):
file = view.file_name()
if file in data:
return [self.get_module(module) for module in data[file] if '.' not in module]
return []


def plugin_loaded():
for win in sublime.windows():
for view in win.views():
initial(view)

0 comments on commit 5281546

Please sign in to comment.