Skip to content

Commit

Permalink
initial commit
Browse files Browse the repository at this point in the history
  • Loading branch information
jvantuyl committed Sep 11, 2011
0 parents commit 09d1898
Show file tree
Hide file tree
Showing 11 changed files with 276 additions and 0 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
*.pyc
3 changes: 3 additions & 0 deletions Default (OSX).sublime-keymap
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
[
{"keys": ["super+m"], "command": "display_diagrams"}
]
23 changes: 23 additions & 0 deletions LICENSE.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
Sublime Editor Plugin
=====================

The Sublime Plug-in software contained herein is Copyright (C) 2011, Jayson
Vantuyl. It is licensed under the Creative Commons
Attribution-NonCommercial-ShareAlike 3.0 Unported license. To view a copy of
the license, visit:

http://creativecommons.org/licenses/by-nc-sa/3.0/legalcode

For alternate licensing arrangements, contact the author at jvantuyl@gmail.com.

Included Software
=================

The included copy of PlantUML is licensed under the GNU General Public License.

For source code, official downloads and licensing information, see
http://plantuml.sourceforge.net. This compiled binary is distributed
unmodified, called at runtime, and is not to be construed as meaningfully part
of this program (i.e. they "communicate at arms length" as mentioned in
http://www.gnu.org/licenses/gpl-faq.html#GPLInProprietarySystem).

5 changes: 5 additions & 0 deletions README.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
This is a plugin for Sublime Text 2. It currently only works on MacOS.

By default, it binds the Command-M key to render any PlantUML diagrams that are
overlapped by any multiselctions. Each diagram will be rendered and they will
all be displayed using QuickLook.
80 changes: 80 additions & 0 deletions diagram/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
from __future__ import absolute_import
from .plantuml import PlantUMLProcessor
from .quicklook import QuickLookViewer
from threading import Thread

INITIALIZED = False
AVAILABLE_PROCESSORS = [PlantUMLProcessor]
AVAILABLE_VIEWERS = [QuickLookViewer]
ACTIVE_PROCESSORS = []
ACTIVE_VIEWER = None


def setup():
global INITIALIZED
global ACTIVE_PROCESSORS
global ACTIVE_VIEWER

for processor in AVAILABLE_PROCESSORS:
try:
proc = processor()
proc.load()
ACTIVE_PROCESSORS.append(proc)
except Exception:
print "Unable to load processor: %r" % processor

for viewer in AVAILABLE_VIEWERS:
try:
vwr = viewer()
vwr.load()
ACTIVE_VIEWER = vwr
break
except Exception:
print "Unable to load viewer: %r" % viewer
else:
raise Exception('No working viewers found!')

INITIALIZED = True
print "Processors: %r" % ACTIVE_PROCESSORS
print "Viewer: %r" % ACTIVE_VIEWER


def process(view):
diagrams = []

for processor in ACTIVE_PROCESSORS:
blocks = []

for block in processor.extract_blocks(view):
add = False
for sel in view.sel():
if sel.intersects(block):
add = True
break
if add:
blocks.append(view.substr(block))

if blocks:
diagrams.append((processor, blocks, ))

if diagrams:
t = Thread(target=render_and_view, args=(diagrams,))
t.daemon = True
t.start()
return True
else:
return False


def render_and_view(diagrams):
print diagrams
diagram_files = []

for processor, blocks in diagrams:
diagram_files.extend(processor.process(blocks))

if diagram_files:
ACTIVE_VIEWER.view(diagram_files)

if not INITIALIZED:
setup()
37 changes: 37 additions & 0 deletions diagram/base.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
class BaseDiagram(object):
def __init__(self, processor, text):
self.proc = processor
self.text = text

def generate(self):
raise NotImplementedError('abstract base class is abstract')


class BaseProcessor(object):
DIAGRAM_CLASS = None

def load(self):
raise NotImplementedError('abstract base class is abstract')

def extract_blocks(self, view):
raise NotImplementedError('abstract base class is abstract')

def process(self, text_blocks):
diagrams = []
for block in text_blocks:
try:
diagram = self.DIAGRAM_CLASS(self, block)
rendered = diagram.generate()
diagrams.append(rendered)
except Exception, e:
print "Error processing diagram: %r" % e
print repr(block)
return diagrams


class BaseViewer(object):
def load(self):
raise NotImplementedError('abstract base class is abstract')

def view(self, filenames):
raise NotImplementedError('abstract base class is abstract')
Binary file added diagram/plantuml-7232.jar
Binary file not shown.
87 changes: 87 additions & 0 deletions diagram/plantuml.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
from __future__ import absolute_import
from .base import BaseDiagram
from .base import BaseProcessor
from subprocess import Popen as execute, PIPE, STDOUT
from os.path import abspath, dirname, exists, join
from tempfile import NamedTemporaryFile


class PlantUMLDiagram(BaseDiagram):
def __init__(self, processor, text):
super(PlantUMLDiagram, self).__init__(processor, text)
self.file = NamedTemporaryFile(suffix='.png')

def generate(self):
puml = execute(
[
'java',
'-jar',
self.proc.plantuml_jar_path,
'-pipe',
'-tpng'
],
stdin=PIPE,
stdout=self.file)
puml.communicate(self.text)
if puml.wait() != 0:
print "Error Processing Diagram:"
print self.text
return
else:
return self.file


class PlantUMLProcessor(BaseProcessor):
DIAGRAM_CLASS = PlantUMLDiagram
PLANTUML_VERSION_STRING = 'PlantUML version 7232'

def load(self):
self.find_plantuml_jar()
self.check_plantuml_version()

def find_plantuml_jar(self):
self.plantuml_jar_file = 'plantuml-%s.jar' % (7232,)
self.plantuml_jar_path = None

self.plantuml_jar_path = abspath(
join(
dirname(__file__),
self.plantuml_jar_file
)
)
assert exists(self.plantuml_jar_path), \
"can't find " + self.plantuml_jar_file

def check_plantuml_version(self):
puml = execute(
[
'java',
'-jar',
self.plantuml_jar_path,
'-version'
],
stdout=PIPE,
stderr=STDOUT
)
version_output = ''
first = True

while first or puml.returncode is None:
first = False
(stdout, stderr) = puml.communicate()
version_output += stdout

print "Version Detection:"
print version_output

assert puml.returncode == 0, "PlantUML returned an error code"
assert self.PLANTUML_VERSION_STRING in version_output, \
"error verifying PlantUML version"

def extract_blocks(self, view):
pairs = (
(
start, view.find('@end', start.begin()))
for start in view.find_all('@start')
)
return (view.full_line(start.cover(end)) for start, end in pairs)
13 changes: 13 additions & 0 deletions diagram/quicklook.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
from .base import BaseViewer
import sys
from subprocess import check_call


class QuickLookViewer(BaseViewer):
def load(self):
assert sys.platform in ('darwin',), "Currently only supported on MacOS"

def view(self, diagram_files):
displaycmd = ['qlmanage', '-p']
displaycmd.extend(diagram_file.name for diagram_file in diagram_files)
check_call(displaycmd)
14 changes: 14 additions & 0 deletions diagram/test.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
Bare Diagram:

@startuml
a --> b
a <-- b
@enduml

Comment Diagram:

# @startuml
# c --> d
# d <-- c
# @enduml

13 changes: 13 additions & 0 deletions diagram_plugin.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
from sublime_plugin import TextCommand
from sublime import error_message
from diagram import setup, process


class DisplayDiagrams(TextCommand):
def run(self, edit):
if not process(self.view):
error_message("No diagrams overlap selections.\n\n" \
"Nothing to process.")

def isEnabled(self):
return True

0 comments on commit 09d1898

Please sign in to comment.