diff --git a/lib/kite-wrapper.js b/lib/kite-wrapper.js new file mode 100644 index 00000000..94156354 --- /dev/null +++ b/lib/kite-wrapper.js @@ -0,0 +1,114 @@ +'use strict' + +const element = require('./decorators/element') +const include = require('./decorators/include') +const {EventsDelegation} = require('atom-utils') +const modules = [ + 'os', 'time', 're', 'sys', 'datetime', 'random', 'django', 'json', 'urllib', + 'subprocess', 'math', 'urllib2', 'logging', 'numpy', 'threading', 'shutil', + 'hashlib', 'socket', 'collections', 'copy', 'itertools', 'traceback', + 'tempfile', 'xml', 'urlparse', 'struct', 'flask', 'StringIO', 'string', + 'optparse', 'base64', 'glob', 'csv', 'requests', 'argparse', 'functools', + 'google', 'pickle', 'ConfigParser', 'matplotlib', 'simplejson', 'south', + 'uuid', 'inspect', 'sqlite3', 'cStringIO', 'operator', 'scipy', 'codecs', + 'unittest', 'pygame', 'cgi', 'getopt', 'cPickle', 'httplib', 'pprint', + 'email', 'BeautifulSoup', 'warnings', 'PIL', 'lxml', 'gtk', 'zipfile', + 'sqlalchemy', 'PyQt4', 'multiprocessing', 'smtplib', 'Queue', 'yaml', + 'twisted', 'MySQLdb', 'select', 'getpass', 'gzip', 'imp', 'ctypes', + 'platform', 'mock', 'wx', 'fnmatch', 'mimetypes', 'fabric', 'signal', + 'pymongo', 'io', 'binascii', 'nose', 'decimal', 'pylab', 'shlex', 'commands', + 'distutils', 'textwrap', 'zlib', 'md5', 'serial', 'calendar', 'hmac', + 'jinja2', 'array', 'fcntl', 'thread', 'unicodedata', 'webbrowser', + 'dateutil', 'werkzeug', 'sublime', 'bottle', 'locale', 'pkg_resources', + 'cookielib', 'gobject', 'feedparser', 'tarfile', 'web', 'nltk', 'httplib2', + 'markdown', 'xmlrpclib', 'boto', 'zope', 'redis', 'heapq', 'ast', 'pdb', + 'Tkinter', 'bisect', 'tornado', 'weakref', 'pyramid', 'psycopg2', 'Crypto', + 'difflib', 'gc', 'HTMLParser', 'gi', 'pwd', 'doctest', 'gevent', 'atexit', + 'gettext', 'networkx', 'curses', 'contextlib', 'pandas', 'exceptions', + 'stat', 'bson', 'pytz', 'sklearn', 'importlib', 'dbus', 'BaseHTTPServer', + 'pygments', 'docutils', 'selenium', 'oauth2', 'twitter', 'scrapy', 'ssl', + 'mako', 'cherrypy', 'shelve', 'paramiko', 'tweepy', 'mechanize', 'types', + 'rospy', 'cv2', 'PySide', 'parser', 'pytest', 'celery', 'posixpath', 'sha', + 'tkFileDialog', 'asyncore', 'tkMessageBox', 'xlrd', 'webob', 'win32api', + 'SocketServer', 'fileinput', 'cv', 'transaction', 'game', 'setuptools', + 'Cookie', 'tests', 'plone', 'xbmcgui', 'code', 'pycurl', 'bz2', 'ftplib', + 'IPython', 'ImageDraw', 'zmq' +] + +class KiteWrapper { + static initClass () { + include(this, EventsDelegation) + return element(this, 'kite-minimap-wrapper') + } + + static isLegible (textEditor) { + const path = textEditor.getPath() + return path && /\.py$/.test(path) && !atom.packages.getLoadedPackage('kite') + } + + static handle (textEditor, minimapElement) { + const matches = [] + textEditor.scan(/(import|from)\s+(\w+)/g, (m) => { + matches.push(m.match[2]) + }) + const links = modules.filter(m => matches.includes(m)).slice(0, 5).map(this.link) + + let wrapper = new this() + wrapper.wrap(minimapElement, this.snippet(links.join(''))) + } + + static snippet (content) { + return ` + docs + + ` + } + + static link (mod) { + return `
  • ${mod}
  • ` + } + + wrap (minimapElement, html) { + minimapElement.parentNode.insertBefore(this, minimapElement) + + const content = document.createElement('div') + content.innerHTML = html + this.appendChild(minimapElement) + this.appendChild(content) + + this.observer = new window.MutationObserver(() => { + this.style.cssText = minimapElement.style.cssText + this.className = minimapElement.className + }) + + this.observer.observe(minimapElement, {attributes: true}) + + const minimap = minimapElement.getModel() + minimap.getScreenHeight = function () { + if (this.isStandAlone()) { + if (this.height != null) { + return this.height + } else { + return this.getHeight() + } + } else { + return minimapElement.clientHeight + } + } + } + + attachedCallback () { + this.subscription = this.subscribeTo(this, '.collapser', { + 'click': () => { + this.querySelector('.collapser').classList.toggle('collapse') + } + }) + } + + detachedCallback () { + this.subscription.dispose() + this.observer.disconnect() + } +} + +module.exports = KiteWrapper.initClass() diff --git a/lib/main.js b/lib/main.js index f340c600..3920dc2d 100644 --- a/lib/main.js +++ b/lib/main.js @@ -16,7 +16,7 @@ if (!atom.inSpecMode()) { const include = require('./decorators/include') const PluginManagement = require('./mixins/plugin-management') -let Emitter, CompositeDisposable, Minimap, MinimapElement, MinimapPluginGeneratorElement +let Emitter, CompositeDisposable, Minimap, MinimapElement, MinimapPluginGeneratorElement, KiteWrapper /** * The `Minimap` package provides an eagle-eye view of text buffers. @@ -386,12 +386,16 @@ class Main { */ initSubscriptions () { this.subscriptions.add(atom.workspace.observeTextEditors((textEditor) => { + if (!KiteWrapper) { KiteWrapper = require('./kite-wrapper') } let minimap = this.minimapForEditor(textEditor) let minimapElement = atom.views.getView(minimap) this.emitter.emit('did-create-minimap', minimap) - minimapElement.attach() + + if (KiteWrapper.isLegible(textEditor)) { + KiteWrapper.handle(textEditor, minimapElement) + } })) } } diff --git a/styles/kite-wrapper.less b/styles/kite-wrapper.less new file mode 100644 index 00000000..ce75be12 --- /dev/null +++ b/styles/kite-wrapper.less @@ -0,0 +1,91 @@ +@import "ui-variables"; + +atom-text-editor, html { + kite-minimap-wrapper { + display: flex; + overflow: hidden; + position: relative; + -webkit-user-select: none; + height: 100%; + order: 3; + width: 10%; + flex: 0 0 10%; + flex-direction: column; + + &.left { + order: 1; + } + + &.absolute { + position: absolute; + right: 0; + + atom-text-editor-minimap:not([stand-alone]) { + position: relative; + } + + &.adjust-absolute-height { + pointer-events: none; + + & > div { + pointer-events: auto; + } + } + + &.left { + position: relative; + right: initial; + } + } + + atom-text-editor-minimap:not([stand-alone]) { + width: 100%; + flex: 1 1 auto; + order: 0; + } + + .collapser { + cursor: pointer; + + i { + height: 16px; + display: inline-block; + vertical-align: middle; + } + + i::before { + transition: transform 0.2s; + margin: 0; + line-height: 1em; + text-align: center; + } + + &.collapse { + i::before { + transform: rotate(-90deg); + } + + & + ul { + display: none; + } + } + } + + & > div { + font-size: 1em; + padding: @component-padding 0; + order: 1; + font-family: sans-serif; + + ul { + margin: 0; + padding: 0; + list-style: none + } + + a { + color: @text-color-info; + } + } + } +}