Editorial Workflows

Plant UML

public workflow

Install Workflow...

This workflow contains at least one Python script. Only use it if you trust the person who shared this with you, and if you know exactly what it does.

I understand, install the workflow!

This is a workflow for Editorial, a Markdown and plain text editor for iOS. To download it, you need to view this page on a device that has the app installed.

Description: Generate UML diagram using plantuml.com.
This workflow uploads text file and get image url from plantuml.com.

Shared by: @stratosphere631

Comments: Comment Feed (RSS)

There are no comments yet.

+ Add Comment

Workflow Preview
Run Python Script ?
Source Code
#coding: utf-8
import editor
import workflow
import json

if sel is None:
	workflow.set_variable('sel', json.dumps((0, 0)))
	workflow.set_variable('sel', json.dumps(sel))
Document Text ?
Folded Text
  • Include
  • Replace with:
Run Python Script ?
Source Code
#coding: utf-8
import workflow
import re
import json

regstartuml = r'@start(\w+)\s*(.+?)\s*$'
regenduml = r'@end(\w+)\s*$'

def get_line_start(lines, _at):
	for c in range(_at, 0, -1):
		if lines[c:c + 1] == '\n':
			return c + 1
	return 0

def search_start(lines):
	p = re.compile(regstartuml, flags=re.MULTILINE)
	m = p.search(lines)
	if m is None:
		return None 
	return m.span()[0], m.group(2)

def search_start_at(lines, _at):
    assert(_at >= 0)
    p = re.compile(regstartuml, flags=re.MULTILINE)
    _from = get_line_start(lines, _at)
    while _from > 0:
        m = p.match(lines, _from)
        if m is not None:
            return (m.span()[0], m.group(2))
        _from = get_line_start(lines, _from - 2)
    return None

def search_end(lines, _from):
	p = re.compile(regenduml, flags=re.MULTILINE)
	m = p.search(lines, _from)
	return m.span()[1] if m else 0

def get_block(lines):
	_from, title = search_start(lines)
	_to = search_end(lines, _from)
	return (title, lines[_from:_to])

def get_block_at(lines, _at):
	_from = search_start_at(lines, _at)
	if _from is None:
		return None
	_to = search_end(lines, _from[0])
	if _to==0:
		return None
	return (_from[1], lines[_from[0]:_to])

if sel[0]==0:
	_block=get_block_at(workflow.get_input(), sel[0])
if _block is None:
Run Python Script ?
Source Code
#coding: utf-8
#!/usr/bin/env python

from zlib import compress

import httplib2

__version__ = 0, 2, 1
__version_string__ = '.'.join(str(x) for x in __version__)

__author__ = 'Doug Napoleone, Samuel Marks'
__email__ = 'doug.napoleone+plantuml@gmail.com'

def deflate_and_encode(plantuml_text):
    """zlib compress the plantuml text and encode it for the plantuml server.
    zlibbed_str = compress(plantuml_text)
    compressed_string = zlibbed_str[2:-4]
    return encode(compressed_string)

def encode(data):
    """encode the plantuml data which may be compresses in the proper
    encoding for the plantuml server
    res = ""
    for i in xrange(0, len(data), 3):
        if i + 2 == len(data):
            res += _encode3bytes(ord(data[i]), ord(data[i + 1]), 0)
        elif i + 1 == len(data):
            res += _encode3bytes(ord(data[i]), 0, 0)
            res += _encode3bytes(ord(data[i]), ord(data[i + 1]), ord(data[i + 2]))
    return res

def _encode3bytes(b1, b2, b3):
    c1 = b1 >> 2
    c2 = ((b1 & 0x3) << 4) | (b2 >> 4)
    c3 = ((b2 & 0xF) << 2) | (b3 >> 6)
    c4 = b3 & 0x3F
    res = ""
    res += _encode6bit(c1 & 0x3F)
    res += _encode6bit(c2 & 0x3F)
    res += _encode6bit(c3 & 0x3F)
    res += _encode6bit(c4 & 0x3F)
    return res

def _encode6bit(b):
    if b < 10:
        return chr(48 + b)
    b -= 10
    if b < 26:
        return chr(65 + b)
    b -= 26
    if b < 26:
        return chr(97 + b)
    b -= 26
    if b == 0:
        return '-'
    if b == 1:
        return '_'
    return '?'

class PlantUML(object):
    """Connection to a PlantUML server with optional authentication.
    All parameters are optional.
    :param str url: URL to the PlantUML server image CGI. defaults to
    :param dict basic_auth: This is if the plantuml server requires basic HTTP
                    authentication. Dictionary containing two keys, 'username'
                    and 'password', set to appropriate values for basic HTTP
    :param dict form_auth: This is for plantuml server requires a cookie based
                    webform login authentication. Dictionary containing two
                    primary keys, 'url' and 'body'. The 'url' should point to
                    the login URL for the server, and the 'body' should be a
                    dictionary set to the form elements required for login.
                    The key 'method' will default to 'POST'. The key 'headers'
                    defaults to
                    Example: form_auth={'url': 'http://example.com/login/',
                    'body': { 'username': 'me', 'password': 'secret'}
    :param dict http_opts: Extra options to be passed off to the
                    httplib2.Http() constructor.
    :param dict request_opts: Extra options to be passed off to the
                    httplib2.Http().request() call.

    def __init__(self, url, basic_auth={}, form_auth={},
                 http_opts={}, request_opts={}):
        self.HttpLib2Error = httplib2.HttpLib2Error
        self.url = url
        self.request_opts = request_opts
        self.auth_type = 'basic_auth' if basic_auth else (
            'form_auth' if form_auth else None)
        self.auth = basic_auth if basic_auth else (
            form_auth if form_auth else None)

        # Proxify
            from urlparse import urlparse
            import socks

            proxy_uri = urlparse(environ.get('HTTPS_PROXY', environ.get('HTTP_PROXY')))
            if proxy_uri:
                proxy = {'proxy_info': httplib2.ProxyInfo(socks.PROXY_TYPE_HTTP,
                                                          proxy_uri.hostname, proxy_uri.port)}
        except ImportError:

        self.http = httplib2.Http(**http_opts)

        if self.auth_type == 'basic_auth':
                self.auth['username'], self.auth['password'])
        elif self.auth_type == 'form_auth':
            if 'url' not in self.auth:
                raise PlantUMLError(
                    "The form_auth option 'url' must be provided and point to "
                    "the login url.")
            if 'body' not in self.auth:
                raise PlantUMLError(
                    "The form_auth option 'body' must be provided and include "
                    "a dictionary with the form elements required to log in. "
                    "Example: form_auth={'url': 'http://example.com/login/', "
                    "'body': { 'username': 'me', 'password': 'secret'}")
            login_url = self.auth['url']
            body = self.auth['body']
            method = self.auth.get('method', 'POST')
            headers = self.auth.get(
                'headers', {'Content-type': 'application/x-www-form-urlencoded'})
                response, content = self.http.request(
                    login_url, method, headers=headers,
            except self.HttpLib2Error, e:
                raise PlantUMLConnectionError(e)
            if response.status != 200:
                raise PlantUMLHTTPError(response, content)
            self.request_opts['Cookie'] = response['set-cookie']

    def get_url(self, plantuml_text):
        """Return the server URL for the image.
        You can use this URL in an IMG HTML tag.
        :param str plantuml_text: The plantuml markup to render
        :returns: the plantuml server image URL
        return self.url + deflate_and_encode(plantuml_text)

import workflow

action_in = workflow.get_input()

pl = PlantUML('http://www.plantuml.com/plantuml/img/')
#TODO: Generate the output...
action_out = pl.get_url(action_in)

Open URL ?
Open in
  • In-App Browser
  • Default App / Safari
  • Last-used Tab
  • New Tab
  • Tab with ID:
Unique identifier
Wait until Loaded
Reveal Browser Automatically