feat(SublimeText2.EditorPackages): cache packages

This commit is contained in:
Iristyle
2013-04-04 08:55:15 -04:00
parent d65666cdfc
commit c3efdad2c2
274 changed files with 26863 additions and 0 deletions

View File

@@ -0,0 +1,2 @@
# Auto detect text files and perform LF normalization
* text=auto

View File

@@ -0,0 +1,2 @@
*.pyc
.DS_Store

View File

@@ -0,0 +1,28 @@
[
{
"caption": "Markdown Preview: preview in Browser",
"command": "markdown_preview",
"args": {
"target": "browser"
}
},
{
"caption": "Markdown Preview: export HTML in Sublime Text",
"command": "markdown_preview",
"args": {
"target": "sublime"
}
},
{
"caption": "Markdown Preview: copy to clipboard",
"command": "markdown_preview",
"args": {
"target": "clipboard"
}
},
{
"caption": "Markdown Preview: open Markdown Cheat sheet",
"command": "markdown_cheatsheet",
"args": {}
}
]

View File

@@ -0,0 +1,35 @@
[
{
"caption": "Preferences",
"mnemonic": "n",
"id": "preferences",
"children":
[
{
"caption": "Package Settings",
"mnemonic": "P",
"id": "package-settings",
"children":
[
{
"caption": "Markdown Preview",
"children":
[
{
"command": "open_file",
"args": {"file": "${packages}/Markdown Preview/MarkdownPreview.sublime-settings"},
"caption": "Settings Default"
},
{
"command": "open_file",
"args": {"file": "${packages}/User/MarkdownPreview.sublime-settings"},
"caption": "Settings User"
},
{ "caption": "-" }
]
}
]
}
]
}
]

View File

@@ -0,0 +1,217 @@
# -*- encoding: UTF-8 -*-
import sublime
import sublime_plugin
import desktop
import tempfile
import markdown2
import os
import sys
import re
import json
import urllib2
settings = sublime.load_settings('MarkdownPreview.sublime-settings')
def getTempMarkdownPreviewPath(view):
''' return a permanent full path of the temp markdown preview file '''
tmp_filename = '%s.html' % view.id()
tmp_fullpath = os.path.join(tempfile.gettempdir(), tmp_filename)
return tmp_fullpath
class MarkdownPreviewListener(sublime_plugin.EventListener):
''' auto update the output html if markdown file has already been converted once '''
def on_post_save(self, view):
if view.file_name().endswith(tuple(settings.get('markdown_filetypes', (".md", ".markdown", ".mdown")))):
temp_file = getTempMarkdownPreviewPath(view)
if os.path.isfile(temp_file):
# reexec markdown conversion
view.run_command('markdown_preview', {'target': 'disk'})
sublime.status_message('Markdown preview file updated')
class MarkdownCheatsheetCommand(sublime_plugin.TextCommand):
''' open our markdown cheat sheet in ST2 '''
def run(self, edit):
cheatsheet = os.path.join(sublime.packages_path(), 'Markdown Preview', 'sample.md')
self.view.window().open_file(cheatsheet)
sublime.status_message('Markdown cheat sheet opened')
class MarkdownPreviewCommand(sublime_plugin.TextCommand):
''' preview file contents with python-markdown and your web browser '''
def getCSS(self):
''' return the correct CSS file based on parser and settings '''
config_parser = settings.get('parser')
config_css = settings.get('css')
styles = ''
if config_css and config_css != 'default':
styles += u"<link href='%s' rel='stylesheet' type='text/css'>" % config_css
else:
css_filename = 'markdown.css'
if config_parser and config_parser == 'github':
css_filename = 'github.css'
# path via package manager
css_path = os.path.join(sublime.packages_path(), 'Markdown Preview', css_filename)
if not os.path.isfile(css_path):
# path via git repo
css_path = os.path.join(sublime.packages_path(), 'sublimetext-markdown-preview', css_filename)
if not os.path.isfile(css_path):
sublime.error_message('markdown.css file not found!')
raise Exception("markdown.css file not found!")
styles += u"<style>%s</style>" % open(css_path, 'r').read().decode('utf-8')
if settings.get('allow_css_overrides'):
filename = self.view.file_name()
filetypes = settings.get('markdown_filetypes')
if filename and filetypes:
for filetype in filetypes:
if filename.endswith(filetype):
css_filename = filename.rpartition(filetype)[0] + '.css'
if (os.path.isfile(css_filename)):
styles += u"<style>%s</style>" % open(css_filename, 'r').read().decode('utf-8')
return styles
def get_contents(self, region):
''' Get contents or selection from view and optionally strip the YAML front matter '''
contents = self.view.substr(region)
# use selection if any
selection = self.view.substr(self.view.sel()[0])
if selection.strip() != '':
contents = selection
if settings.get('strip_yaml_front_matter') and contents.startswith('---'):
title = ''
title_match = re.search('(?:title:)(.+)', contents, flags=re.IGNORECASE)
if title_match:
stripped_title = title_match.group(1).strip()
title = '%s\n%s\n\n' % (stripped_title, '=' * len(stripped_title))
contents_without_front_matter = re.sub(r'(?s)^---.*---\n', '', contents)
contents = '%s%s' % (title, contents_without_front_matter)
return contents
def postprocessor(self, html):
''' fix relative paths in images, scripts, and links for the internal parser '''
def tag_fix(match):
tag, src = match.groups()
filename = self.view.file_name()
if filename:
if not src.startswith(('file://', 'https://', 'http://', '/', '#')):
abs_path = u'file://%s/%s' % (os.path.dirname(filename), src)
tag = tag.replace(src, abs_path)
return tag
RE_SOURCES = re.compile("""(?P<tag><(?:img|script|a)[^>]+(?:src|href)=["'](?P<src>[^"']+)[^>]*>)""")
html = RE_SOURCES.sub(tag_fix, html)
return html
def convert_markdown(self, markdown):
''' convert input markdown to HTML, with github or builtin parser '''
config_parser = settings.get('parser')
github_oauth_token = settings.get('github_oauth_token')
markdown_html = u'cannot convert markdown'
if config_parser and config_parser == 'github':
# use the github API
sublime.status_message('converting markdown with github API...')
try:
github_mode = settings.get('github_mode', 'gfm')
data = {"text": markdown, "mode": github_mode}
json_data = json.dumps(data)
url = "https://api.github.com/markdown"
sublime.status_message(url)
request = urllib2.Request(url, json_data, {'Content-Type': 'application/json'})
if github_oauth_token:
request.add_header('Authorization', "token %s" % github_oauth_token)
markdown_html = urllib2.urlopen(request).read().decode('utf-8')
except urllib2.HTTPError, e:
if e.code == 401:
sublime.error_message('github API auth failed. Please check your OAuth token.')
else:
sublime.error_message('github API responded in an unfashion way :/')
except urllib2.URLError:
sublime.error_message('cannot use github API to convert markdown. SSL is not included in your Python installation')
except:
sublime.error_message('cannot use github API to convert markdown. Please check your settings.')
else:
sublime.status_message('converted markdown with github API successfully')
else:
# convert the markdown
markdown_html = markdown2.markdown(markdown, extras=['footnotes', 'toc', 'fenced-code-blocks', 'cuddled-lists'])
toc_html = markdown_html.toc_html
if toc_html:
toc_markers = ['[toc]', '[TOC]', '<!--TOC-->']
for marker in toc_markers:
markdown_html = markdown_html.replace(marker, toc_html)
# postprocess the html from internal parser
markdown_html = self.postprocessor(markdown_html)
return markdown_html
def run(self, edit, target='browser'):
region = sublime.Region(0, self.view.size())
encoding = self.view.encoding()
if encoding == 'Undefined':
encoding = 'utf-8'
elif encoding == 'Western (Windows 1252)':
encoding = 'windows-1252'
elif encoding == 'UTF-8 with BOM':
encoding = 'utf-8'
contents = self.get_contents(region)
markdown_html = self.convert_markdown(contents)
full_html = u'<!DOCTYPE html>'
full_html += '<html><head><meta charset="%s">' % encoding
full_html += self.getCSS()
full_html += '</head><body>'
full_html += markdown_html
full_html += '</body>'
full_html += '</html>'
if target in ['disk', 'browser']:
# check if LiveReload ST2 extension installed and add its script to the resulting HTML
livereload_installed = ('LiveReload' in os.listdir(sublime.packages_path()))
if livereload_installed:
full_html += '<script>document.write(\'<script src="http://\' + (location.host || \'localhost\').split(\':\')[0] + \':35729/livereload.js?snipver=1"></\' + \'script>\')</script>'
# update output html file
tmp_fullpath = getTempMarkdownPreviewPath(self.view)
tmp_html = open(tmp_fullpath, 'w')
tmp_html.write(full_html.encode(encoding))
tmp_html.close()
# now opens in browser if needed
if target == 'browser':
config_browser = settings.get('browser')
if config_browser and config_browser != 'default':
cmd = '"%s" %s' % (config_browser, tmp_fullpath)
if sys.platform == 'darwin':
cmd = "open -a %s" % cmd
elif sys.platform == 'linux2':
cmd += ' &'
result = os.system(cmd)
if result != 0:
sublime.error_message('cannot execute "%s" Please check your Markdown Preview settings' % config_browser)
else:
sublime.status_message('Markdown preview launched in %s' % config_browser)
else:
desktop.open(tmp_fullpath)
sublime.status_message('Markdown preview launched in default html viewer')
elif target == 'sublime':
# create a new buffer and paste the output HTML
new_view = self.view.window().new_file()
new_view.set_scratch(True)
new_edit = new_view.begin_edit()
new_view.insert(new_edit, 0, markdown_html)
new_view.end_edit(new_edit)
sublime.status_message('Markdown preview launched in sublime')
elif target == 'clipboard':
# clipboard copy the full HTML
sublime.set_clipboard(full_html)
sublime.status_message('Markdown export copied to clipboard')

View File

@@ -0,0 +1,60 @@
/*
Markdown Preview default settings
*/
{
/*
Sets the default opener for html files
default - Use the system default HTML viewer
other - Set a full path to any executable. ex: /Applications/Google Chrome Canary.app or /Applications/Firefox.app
*/
"browser": "default",
/*
Sets the default parser for converting markdown to html.
Warning for github API : if you have a ST2 linux build, Python is not built with SSL o it may not work
default - Use the builtin python-markdown2 parser
github - User github API to convert markdown, so you can use GitHub flavored Markdown, see http://github.github.com/github-flavored-markdown/
*/
"parser": "default",
/*
Default mode for the github Markdon parser : markdown (documents) or gfm (comments)
see http://developer.github.com/v3/markdown/#render-an-arbitrary-markdown-document
*/
"github_mode": "markdown",
/*
Uses an OAuth token to when parsing markdown with GitHub API. To create one for Markdown Preview, see https://help.github.com/articles/creating-an-oauth-token-for-command-line-use.
*/
// "github_oauth_token": "secret"
/*
Sets the default css file to embed in the HTML
default - Use the builtin CSS or github CSS, depending on parser config (markdown.css or github.css)
other - Set an absolute path or url to any css file
*/
"css": "default",
/*
Allow CSS overrides
true - Any file with matching a .markdown_filetype extension with .css will be loaded as an override
false - Matching files ignored
*/
"allow_css_overrides": true,
/*
Sets the supported filetypes for auto-reload on save
*/
"markdown_filetypes": [".md", ".markdown", ".mdown"],
/*
Strips the YAML front matter header and converts title to a heading
*/
"strip_yaml_front_matter": false
}

View File

@@ -0,0 +1,52 @@
Sublime Text 2 MarkDown preview
===============================
A simple ST2 plugin to help you preview your markdown files quickly in you web browser.
You can use builtin [python-markdown2][0] parser (default) or use the [github markdown API][5] for the conversion (edit your settings to select it).
**NOTE:** If you choose the GitHub API for conversion (set parser: github in your settings), your code will be sent through https to github for live conversion. You'll have [Github flavored markdown][6], syntax highlighting and EMOJI support for free :heart: :octocat: :gift:. If you make more than 60 calls a day, be sure to set your GitHub API key in the settings :)
**LINUX users:** If you want to use GitHub API for conversion, you'll need to have a custom Python install that includes python-ssl as its not built in the Sublime Text 2 Linux package. see [@dusteye comment][8]. If you use a custom window manager, also be sure to set a `BROWSER` environnement variable. see [@PPvG comments][9]
## Features :
- Markdown conversion via builtin Markdown Parser ([python-markdown2][0]) or via Github API : just choose in your settings.
- Browser preview auto reload on save if you have the [ST2 LiveReload plugin][7] installed.
- Builtin parser : Support TOC, footnotes markdown extensions
- CSS overriding if you need
- YAML support thanks to @tommi
- Clipboard selection and copy to clipboard thanks to @hexatrope
## Installation :
- you should use [sublime package manager][3]
- use `cmd+shift+P` then `Package Control: Install Package`
- look for `Markdown Preview` and install it.
## Usage :
- optionnaly select some of your markdown for conversion
- use `cmd+shift+P` then `Markdown Preview` to launch a preview
- or bind some key in your user key binding, using a line like this one:
`{ "keys": ["alt+m"], "command": "markdown_preview", "args": {"target": "browser"} },`
- once converted a first time, the output HTML will be updated on each file save (with LiveReload plugin)
## Uses :
- [python-markdown2][0] for markdown parsing **OR** the GitHub markdown API.
## Licence :
The code is available at github [https://github.com/revolunet/sublimetext-markdown-preview][2] under MIT licence : [http://revolunet.mit-license.org][4]
[0]: https://github.com/trentm/python-markdown2
[2]: https://github.com/revolunet/sublimetext-markdown-preview
[3]: http://wbond.net/sublime_packages/package_control
[4]: http://revolunet.mit-license.org
[5]: http://developer.github.com/v3/markdown
[6]: http://github.github.com/github-flavored-markdown/
[7]: https://github.com/dz0ny/LiveReload-sublimetext2
[8]: https://github.com/revolunet/sublimetext-markdown-preview/issues/27#issuecomment-11772098
[9]: https://github.com/revolunet/sublimetext-markdown-preview/issues/78#issuecomment-15644727

View File

@@ -0,0 +1,290 @@
#!/usr/bin/env python
"""
Simple desktop integration for Python. This module provides desktop environment
detection and resource opening support for a selection of common and
standardised desktop environments.
Copyright (C) 2005, 2006, 2007, 2008, 2009 Paul Boddie <paul@boddie.org.uk>
This program is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License as published by the Free
Software Foundation; either version 3 of the License, or (at your option) any
later version.
This program is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
details.
You should have received a copy of the GNU Lesser General Public License along
with this program. If not, see <http://www.gnu.org/licenses/>.
--------
Desktop Detection
-----------------
To detect a specific desktop environment, use the get_desktop function.
To detect whether the desktop environment is standardised (according to the
proposed DESKTOP_LAUNCH standard), use the is_standard function.
Opening URLs
------------
To open a URL in the current desktop environment, relying on the automatic
detection of that environment, use the desktop.open function as follows:
desktop.open("http://www.python.org")
To override the detected desktop, specify the desktop parameter to the open
function as follows:
desktop.open("http://www.python.org", "KDE") # Insists on KDE
desktop.open("http://www.python.org", "GNOME") # Insists on GNOME
desktop.open("http://www.python.org", "MATE") # Insists on MATE
Without overriding using the desktop parameter, the open function will attempt
to use the "standard" desktop opening mechanism which is controlled by the
DESKTOP_LAUNCH environment variable as described below.
The DESKTOP_LAUNCH Environment Variable
---------------------------------------
The DESKTOP_LAUNCH environment variable must be shell-quoted where appropriate,
as shown in some of the following examples:
DESKTOP_LAUNCH="kdialog --msgbox" Should present any opened URLs in
their entirety in a KDE message box.
(Command "kdialog" plus parameter.)
DESKTOP_LAUNCH="my\ opener" Should run the "my opener" program to
open URLs.
(Command "my opener", no parameters.)
DESKTOP_LAUNCH="my\ opener --url" Should run the "my opener" program to
open URLs.
(Command "my opener" plus parameter.)
Details of the DESKTOP_LAUNCH environment variable convention can be found here:
http://lists.freedesktop.org/archives/xdg/2004-August/004489.html
Other Modules
-------------
The desktop.dialog module provides support for opening dialogue boxes.
The desktop.windows module permits the inspection of desktop windows.
"""
__version__ = "0.4"
import os
import sys
# Provide suitable process creation functions.
try:
import subprocess
def _run(cmd, shell, wait):
opener = subprocess.Popen(cmd, shell=shell)
if wait: opener.wait()
return opener.pid
def _readfrom(cmd, shell):
opener = subprocess.Popen(cmd, shell=shell, stdin=subprocess.PIPE, stdout=subprocess.PIPE)
opener.stdin.close()
return opener.stdout.read()
def _status(cmd, shell):
opener = subprocess.Popen(cmd, shell=shell)
opener.wait()
return opener.returncode == 0
except ImportError:
import popen2
def _run(cmd, shell, wait):
opener = popen2.Popen3(cmd)
if wait: opener.wait()
return opener.pid
def _readfrom(cmd, shell):
opener = popen2.Popen3(cmd)
opener.tochild.close()
opener.childerr.close()
return opener.fromchild.read()
def _status(cmd, shell):
opener = popen2.Popen3(cmd)
opener.wait()
return opener.poll() == 0
import commands
# Private functions.
def _get_x11_vars():
"Return suitable environment definitions for X11."
if not os.environ.get("DISPLAY", "").strip():
return "DISPLAY=:0.0 "
else:
return ""
def _is_xfce():
"Return whether XFCE is in use."
# XFCE detection involves testing the output of a program.
try:
return _readfrom(_get_x11_vars() + "xprop -root _DT_SAVE_MODE", shell=1).strip().endswith(' = "xfce4"')
except OSError:
return 0
def _is_x11():
"Return whether the X Window System is in use."
return os.environ.has_key("DISPLAY")
# Introspection functions.
def get_desktop():
"""
Detect the current desktop environment, returning the name of the
environment. If no environment could be detected, None is returned.
"""
if os.environ.has_key("KDE_FULL_SESSION") or \
os.environ.has_key("KDE_MULTIHEAD"):
return "KDE"
elif os.environ.has_key("GNOME_DESKTOP_SESSION_ID") or \
os.environ.has_key("GNOME_KEYRING_SOCKET"):
return "GNOME"
elif os.environ.has_key("MATE_DESKTOP_SESSION_ID") or \
os.environ.has_key("MATE_KEYRING_SOCKET"):
return "MATE"
elif sys.platform == "darwin":
return "Mac OS X"
elif hasattr(os, "startfile"):
return "Windows"
elif _is_xfce():
return "XFCE"
# KDE, GNOME, MATE and XFCE run on X11, so we have to test for X11 last.
if _is_x11():
return "X11"
else:
return None
def use_desktop(desktop):
"""
Decide which desktop should be used, based on the detected desktop and a
supplied 'desktop' argument (which may be None). Return an identifier
indicating the desktop type as being either "standard" or one of the results
from the 'get_desktop' function.
"""
# Attempt to detect a desktop environment.
detected = get_desktop()
# Start with desktops whose existence can be easily tested.
if (desktop is None or desktop == "standard") and is_standard():
return "standard"
elif (desktop is None or desktop == "Windows") and detected == "Windows":
return "Windows"
# Test for desktops where the overriding is not verified.
elif (desktop or detected) == "KDE":
return "KDE"
elif (desktop or detected) == "GNOME":
return "GNOME"
elif (desktop or detected) == "MATE":
return "MATE"
elif (desktop or detected) == "XFCE":
return "XFCE"
elif (desktop or detected) == "Mac OS X":
return "Mac OS X"
elif (desktop or detected) == "X11":
return "X11"
else:
return None
def is_standard():
"""
Return whether the current desktop supports standardised application
launching.
"""
return os.environ.has_key("DESKTOP_LAUNCH")
# Activity functions.
def open(url, desktop=None, wait=0):
"""
Open the 'url' in the current desktop's preferred file browser. If the
optional 'desktop' parameter is specified then attempt to use that
particular desktop environment's mechanisms to open the 'url' instead of
guessing or detecting which environment is being used.
Suggested values for 'desktop' are "standard", "KDE", "GNOME", "GNOME",
"XFCE", "Mac OS X", "Windows" where "standard" employs a DESKTOP_LAUNCH
environment variable to open the specified 'url'. DESKTOP_LAUNCH should
be a command, possibly followed by arguments, and must have any special
characters shell-escaped.
The process identifier of the "opener" (ie. viewer, editor, browser or
program) associated with the 'url' is returned by this function. If the
process identifier cannot be determined, None is returned.
An optional 'wait' parameter is also available for advanced usage and, if
'wait' is set to a true value, this function will wait for the launching
mechanism to complete before returning (as opposed to immediately returning
as is the default behaviour).
"""
# Decide on the desktop environment in use.
desktop_in_use = use_desktop(desktop)
if desktop_in_use == "standard":
arg = "".join([os.environ["DESKTOP_LAUNCH"], commands.mkarg(url)])
return _run(arg, 1, wait)
elif desktop_in_use == "Windows":
# NOTE: This returns None in current implementations.
return os.startfile(url)
elif desktop_in_use == "KDE":
cmd = ["xdg-open", url]
elif desktop_in_use == "GNOME":
cmd = ["xdg-open", url]
elif desktop_in_use == "MATE":
cmd = ["xdg-open", url]
elif desktop_in_use == "XFCE":
cmd = ["xdg-open", url]
elif desktop_in_use == "Mac OS X":
cmd = ["open", url]
elif desktop_in_use == "X11" and os.environ.has_key("BROWSER"):
cmd = [os.environ["BROWSER"], url]
# Finish with an error where no suitable desktop was identified.
else:
raise OSError, "Desktop '%s' not supported (neither DESKTOP_LAUNCH nor os.startfile could be used)" % desktop_in_use
return _run(cmd, 0, wait)
# vim: tabstop=4 expandtab shiftwidth=4

View File

@@ -0,0 +1,551 @@
#!/usr/bin/env python
"""
Simple desktop dialogue box support for Python.
Copyright (C) 2007, 2009 Paul Boddie <paul@boddie.org.uk>
This program is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License as published by the Free
Software Foundation; either version 3 of the License, or (at your option) any
later version.
This program is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
details.
You should have received a copy of the GNU Lesser General Public License along
with this program. If not, see <http://www.gnu.org/licenses/>.
--------
Opening Dialogue Boxes (Dialogs)
--------------------------------
To open a dialogue box (dialog) in the current desktop environment, relying on
the automatic detection of that environment, use the appropriate dialogue box
class:
question = desktop.dialog.Question("Are you sure?")
result = question.open()
To override the detected desktop, specify the desktop parameter to the open
function as follows:
question.open("KDE") # Insists on KDE
question.open("GNOME") # Insists on GNOME
question.open("MATE") # Insists on MATE
The dialogue box options are documented in each class's docstring.
Available dialogue box classes are listed in the desktop.dialog.available
attribute.
Supported desktop environments are listed in the desktop.dialog.supported
attribute.
"""
from desktop import use_desktop, _run, _readfrom, _status
class _wrapper:
def __init__(self, handler):
self.handler = handler
class _readvalue(_wrapper):
def __call__(self, cmd, shell):
return self.handler(cmd, shell).strip()
class _readinput(_wrapper):
def __call__(self, cmd, shell):
return self.handler(cmd, shell)[:-1]
class _readvalues_kdialog(_wrapper):
def __call__(self, cmd, shell):
result = self.handler(cmd, shell).strip().strip('"')
if result:
return result.split('" "')
else:
return []
class _readvalues_zenity(_wrapper):
def __call__(self, cmd, shell):
result = self.handler(cmd, shell).strip()
if result:
return result.split("|")
else:
return []
class _readvalues_Xdialog(_wrapper):
def __call__(self, cmd, shell):
result = self.handler(cmd, shell).strip()
if result:
return result.split("/")
else:
return []
# Dialogue parameter classes.
class String:
"A generic parameter."
def __init__(self, name):
self.name = name
def convert(self, value, program):
return [value or ""]
class Strings(String):
"Multiple string parameters."
def convert(self, value, program):
return value or []
class StringPairs(String):
"Multiple string parameters duplicated to make identifiers."
def convert(self, value, program):
l = []
for v in value:
l.append(v)
l.append(v)
return l
class StringKeyword:
"A keyword parameter."
def __init__(self, keyword, name):
self.keyword = keyword
self.name = name
def convert(self, value, program):
return [self.keyword + "=" + (value or "")]
class StringKeywords:
"Multiple keyword parameters."
def __init__(self, keyword, name):
self.keyword = keyword
self.name = name
def convert(self, value, program):
l = []
for v in value or []:
l.append(self.keyword + "=" + v)
return l
class Integer(String):
"An integer parameter."
defaults = {
"width" : 40,
"height" : 15,
"list_height" : 10
}
scale = 8
def __init__(self, name, pixels=0):
String.__init__(self, name)
if pixels:
self.factor = self.scale
else:
self.factor = 1
def convert(self, value, program):
if value is None:
value = self.defaults[self.name]
return [str(int(value) * self.factor)]
class IntegerKeyword(Integer):
"An integer keyword parameter."
def __init__(self, keyword, name, pixels=0):
Integer.__init__(self, name, pixels)
self.keyword = keyword
def convert(self, value, program):
if value is None:
value = self.defaults[self.name]
return [self.keyword + "=" + str(int(value) * self.factor)]
class Boolean(String):
"A boolean parameter."
values = {
"kdialog" : ["off", "on"],
"zenity" : ["FALSE", "TRUE"],
"Xdialog" : ["off", "on"]
}
def convert(self, value, program):
values = self.values[program]
if value:
return [values[1]]
else:
return [values[0]]
class MenuItemList(String):
"A menu item list parameter."
def convert(self, value, program):
l = []
for v in value:
l.append(v.value)
l.append(v.text)
return l
class ListItemList(String):
"A radiolist/checklist item list parameter."
def __init__(self, name, status_first=0):
String.__init__(self, name)
self.status_first = status_first
def convert(self, value, program):
l = []
for v in value:
boolean = Boolean(None)
status = boolean.convert(v.status, program)
if self.status_first:
l += status
l.append(v.value)
l.append(v.text)
if not self.status_first:
l += status
return l
# Dialogue argument values.
class MenuItem:
"A menu item which can also be used with radiolists and checklists."
def __init__(self, value, text, status=0):
self.value = value
self.text = text
self.status = status
# Dialogue classes.
class Dialogue:
commands = {
"KDE" : "kdialog",
"GNOME" : "zenity",
"MATE" : "zenity",
"XFCE" : "zenity", # NOTE: Based on observations with Xubuntu.
"X11" : "Xdialog"
}
def open(self, desktop=None):
"""
Open a dialogue box (dialog) using a program appropriate to the desktop
environment in use.
If the optional 'desktop' parameter is specified then attempt to use
that particular desktop environment's mechanisms to open the dialog
instead of guessing or detecting which environment is being used.
Suggested values for 'desktop' are "standard", "KDE", "GNOME",
"MATE", "Mac OS X", "Windows".
The result of the dialogue interaction may be a string indicating user
input (for Input, Password, Menu, Pulldown), a list of strings
indicating selections of one or more items (for RadioList, CheckList),
or a value indicating true or false (for Question, Warning, Message,
Error).
Where a string value may be expected but no choice is made, an empty
string may be returned. Similarly, where a list of values is expected
but no choice is made, an empty list may be returned.
"""
# Decide on the desktop environment in use.
desktop_in_use = use_desktop(desktop)
# Get the program.
try:
program = self.commands[desktop_in_use]
except KeyError:
raise OSError, "Desktop '%s' not supported (no known dialogue box command could be suggested)" % desktop_in_use
# The handler is one of the functions communicating with the subprocess.
# Some handlers return boolean values, others strings.
handler, options = self.info[program]
cmd = [program]
for option in options:
if isinstance(option, str):
cmd.append(option)
else:
value = getattr(self, option.name, None)
cmd += option.convert(value, program)
return handler(cmd, 0)
class Simple(Dialogue):
def __init__(self, text, width=None, height=None):
self.text = text
self.width = width
self.height = height
class Question(Simple):
"""
A dialogue asking a question and showing response buttons.
Options: text, width (in characters), height (in characters)
Response: a boolean value indicating an affirmative response (true) or a
negative response
"""
name = "question"
info = {
"kdialog" : (_status, ["--yesno", String("text")]),
"zenity" : (_status, ["--question", StringKeyword("--text", "text")]),
"Xdialog" : (_status, ["--stdout", "--yesno", String("text"), Integer("height"), Integer("width")]),
}
class Warning(Simple):
"""
A dialogue asking a question and showing response buttons.
Options: text, width (in characters), height (in characters)
Response: a boolean value indicating an affirmative response (true) or a
negative response
"""
name = "warning"
info = {
"kdialog" : (_status, ["--warningyesno", String("text")]),
"zenity" : (_status, ["--warning", StringKeyword("--text", "text")]),
"Xdialog" : (_status, ["--stdout", "--yesno", String("text"), Integer("height"), Integer("width")]),
}
class Message(Simple):
"""
A message dialogue.
Options: text, width (in characters), height (in characters)
Response: a boolean value indicating an affirmative response (true) or a
negative response
"""
name = "message"
info = {
"kdialog" : (_status, ["--msgbox", String("text")]),
"zenity" : (_status, ["--info", StringKeyword("--text", "text")]),
"Xdialog" : (_status, ["--stdout", "--msgbox", String("text"), Integer("height"), Integer("width")]),
}
class Error(Simple):
"""
An error dialogue.
Options: text, width (in characters), height (in characters)
Response: a boolean value indicating an affirmative response (true) or a
negative response
"""
name = "error"
info = {
"kdialog" : (_status, ["--error", String("text")]),
"zenity" : (_status, ["--error", StringKeyword("--text", "text")]),
"Xdialog" : (_status, ["--stdout", "--msgbox", String("text"), Integer("height"), Integer("width")]),
}
class Menu(Simple):
"""
A menu of options, one of which being selectable.
Options: text, width (in characters), height (in characters),
list_height (in items), items (MenuItem objects)
Response: a value corresponding to the chosen item
"""
name = "menu"
info = {
"kdialog" : (_readvalue(_readfrom), ["--menu", String("text"), MenuItemList("items")]),
"zenity" : (_readvalue(_readfrom), ["--list", StringKeyword("--text", "text"), StringKeywords("--column", "titles"),
MenuItemList("items")]
),
"Xdialog" : (_readvalue(_readfrom), ["--stdout", "--menubox",
String("text"), Integer("height"), Integer("width"), Integer("list_height"), MenuItemList("items")]
),
}
item = MenuItem
number_of_titles = 2
def __init__(self, text, titles, items=None, width=None, height=None, list_height=None):
"""
Initialise a menu with the given heading 'text', column 'titles', and
optional 'items' (which may be added later), 'width' (in characters),
'height' (in characters) and 'list_height' (in items).
"""
Simple.__init__(self, text, width, height)
self.titles = ([""] * self.number_of_titles + titles)[-self.number_of_titles:]
self.items = items or []
self.list_height = list_height
def add(self, *args, **kw):
"""
Add an item, passing the given arguments to the appropriate item class.
"""
self.items.append(self.item(*args, **kw))
class RadioList(Menu):
"""
A list of radio buttons, one of which being selectable.
Options: text, width (in characters), height (in characters),
list_height (in items), items (MenuItem objects), titles
Response: a list of values corresponding to chosen items (since some
programs, eg. zenity, appear to support multiple default
selections)
"""
name = "radiolist"
info = {
"kdialog" : (_readvalues_kdialog(_readfrom), ["--radiolist", String("text"), ListItemList("items")]),
"zenity" : (_readvalues_zenity(_readfrom),
["--list", "--radiolist", StringKeyword("--text", "text"), StringKeywords("--column", "titles"),
ListItemList("items", 1)]
),
"Xdialog" : (_readvalues_Xdialog(_readfrom), ["--stdout", "--radiolist",
String("text"), Integer("height"), Integer("width"), Integer("list_height"), ListItemList("items")]
),
}
number_of_titles = 3
class CheckList(Menu):
"""
A list of checkboxes, many being selectable.
Options: text, width (in characters), height (in characters),
list_height (in items), items (MenuItem objects), titles
Response: a list of values corresponding to chosen items
"""
name = "checklist"
info = {
"kdialog" : (_readvalues_kdialog(_readfrom), ["--checklist", String("text"), ListItemList("items")]),
"zenity" : (_readvalues_zenity(_readfrom),
["--list", "--checklist", StringKeyword("--text", "text"), StringKeywords("--column", "titles"),
ListItemList("items", 1)]
),
"Xdialog" : (_readvalues_Xdialog(_readfrom), ["--stdout", "--checklist",
String("text"), Integer("height"), Integer("width"), Integer("list_height"), ListItemList("items")]
),
}
number_of_titles = 3
class Pulldown(Menu):
"""
A pull-down menu of options, one of which being selectable.
Options: text, width (in characters), height (in characters),
items (list of values)
Response: a value corresponding to the chosen item
"""
name = "pulldown"
info = {
"kdialog" : (_readvalue(_readfrom), ["--combobox", String("text"), Strings("items")]),
"zenity" : (_readvalue(_readfrom),
["--list", "--radiolist", StringKeyword("--text", "text"), StringKeywords("--column", "titles"),
StringPairs("items")]
),
"Xdialog" : (_readvalue(_readfrom),
["--stdout", "--combobox", String("text"), Integer("height"), Integer("width"), Strings("items")]),
}
item = unicode
number_of_titles = 2
class Input(Simple):
"""
An input dialogue, consisting of an input field.
Options: text, input, width (in characters), height (in characters)
Response: the text entered into the dialogue by the user
"""
name = "input"
info = {
"kdialog" : (_readinput(_readfrom),
["--inputbox", String("text"), String("data")]),
"zenity" : (_readinput(_readfrom),
["--entry", StringKeyword("--text", "text"), StringKeyword("--entry-text", "data")]),
"Xdialog" : (_readinput(_readfrom),
["--stdout", "--inputbox", String("text"), Integer("height"), Integer("width"), String("data")]),
}
def __init__(self, text, data="", width=None, height=None):
Simple.__init__(self, text, width, height)
self.data = data
class Password(Input):
"""
A password dialogue, consisting of a password entry field.
Options: text, width (in characters), height (in characters)
Response: the text entered into the dialogue by the user
"""
name = "password"
info = {
"kdialog" : (_readinput(_readfrom),
["--password", String("text")]),
"zenity" : (_readinput(_readfrom),
["--entry", StringKeyword("--text", "text"), "--hide-text"]),
"Xdialog" : (_readinput(_readfrom),
["--stdout", "--password", "--inputbox", String("text"), Integer("height"), Integer("width")]),
}
class TextFile(Simple):
"""
A text file input box.
Options: filename, text, width (in characters), height (in characters)
Response: any text returned by the dialogue program (typically an empty
string)
"""
name = "textfile"
info = {
"kdialog" : (_readfrom, ["--textbox", String("filename"), Integer("width", pixels=1), Integer("height", pixels=1)]),
"zenity" : (_readfrom, ["--text-info", StringKeyword("--filename", "filename"), IntegerKeyword("--width", "width", pixels=1),
IntegerKeyword("--height", "height", pixels=1)]
),
"Xdialog" : (_readfrom, ["--stdout", "--textbox", String("filename"), Integer("height"), Integer("width")]),
}
def __init__(self, filename, text="", width=None, height=None):
Simple.__init__(self, text, width, height)
self.filename = filename
# Available dialogues.
available = [Question, Warning, Message, Error, Menu, CheckList, RadioList, Input, Password, Pulldown, TextFile]
# Supported desktop environments.
supported = Dialogue.commands.keys()
# vim: tabstop=4 expandtab shiftwidth=4

View File

@@ -0,0 +1,273 @@
#!/usr/bin/env python
"""
Simple desktop window enumeration for Python.
Copyright (C) 2007, 2008, 2009 Paul Boddie <paul@boddie.org.uk>
This program is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License as published by the Free
Software Foundation; either version 3 of the License, or (at your option) any
later version.
This program is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
details.
You should have received a copy of the GNU Lesser General Public License along
with this program. If not, see <http://www.gnu.org/licenses/>.
--------
Finding Open Windows on the Desktop
-----------------------------------
To obtain a list of windows, use the desktop.windows.list function as follows:
windows = desktop.windows.list()
To obtain the root window, typically the desktop background, use the
desktop.windows.root function as follows:
root = desktop.windows.root()
Each window object can be inspected through a number of methods. For example:
name = window.name()
width, height = window.size()
x, y = window.position()
child_windows = window.children()
See the desktop.windows.Window class for more information.
"""
from desktop import _is_x11, _get_x11_vars, _readfrom, use_desktop
import re
# System functions.
def _xwininfo(identifier, action):
if identifier is None:
args = "-root"
else:
args = "-id " + identifier
s = _readfrom(_get_x11_vars() + "xwininfo %s -%s" % (args, action), shell=1)
# Return a mapping of keys to values for the "stats" action.
if action == "stats":
d = {}
for line in s.split("\n"):
fields = line.split(":")
if len(fields) < 2:
continue
key, value = fields[0].strip(), ":".join(fields[1:]).strip()
d[key] = value
return d
# Otherwise, return the raw output.
else:
return s
def _get_int_properties(d, properties):
results = []
for property in properties:
results.append(int(d[property]))
return results
# Finder functions.
def find_all(name):
return 1
def find_named(name):
return name is not None
def find_by_name(name):
return lambda n, t=name: n == t
# Window classes.
# NOTE: X11 is the only supported desktop so far.
class Window:
"A window on the desktop."
_name_pattern = re.compile(r':\s+\(.*?\)\s+[-0-9x+]+\s+[-0-9+]+$')
_absent_names = "(has no name)", "(the root window) (has no name)"
def __init__(self, identifier):
"Initialise the window with the given 'identifier'."
self.identifier = identifier
# Finder methods (from above).
self.find_all = find_all
self.find_named = find_named
self.find_by_name = find_by_name
def __repr__(self):
return "Window(%r)" % self.identifier
# Methods which deal with the underlying commands.
def _get_handle_and_name(self, text):
fields = text.strip().split(" ")
handle = fields[0]
# Get the "<name>" part, stripping off the quotes.
name = " ".join(fields[1:])
if len(name) > 1 and name[0] == '"' and name[-1] == '"':
name = name[1:-1]
if name in self._absent_names:
return handle, None
else:
return handle, name
def _get_this_handle_and_name(self, line):
fields = line.split(":")
return self._get_handle_and_name(":".join(fields[1:]))
def _get_descendant_handle_and_name(self, line):
match = self._name_pattern.search(line)
if match:
return self._get_handle_and_name(line[:match.start()].strip())
else:
raise OSError, "Window information from %r did not contain window details." % line
def _descendants(self, s, fn):
handles = []
adding = 0
for line in s.split("\n"):
if line.endswith("child:") or line.endswith("children:"):
if not adding:
adding = 1
elif adding and line:
handle, name = self._get_descendant_handle_and_name(line)
if fn(name):
handles.append(handle)
return [Window(handle) for handle in handles]
# Public methods.
def children(self, all=0):
"""
Return a list of windows which are children of this window. If the
optional 'all' parameter is set to a true value, all such windows will
be returned regardless of whether they have any name information.
"""
s = _xwininfo(self.identifier, "children")
return self._descendants(s, all and self.find_all or self.find_named)
def descendants(self, all=0):
"""
Return a list of windows which are descendants of this window. If the
optional 'all' parameter is set to a true value, all such windows will
be returned regardless of whether they have any name information.
"""
s = _xwininfo(self.identifier, "tree")
return self._descendants(s, all and self.find_all or self.find_named)
def find(self, callable):
"""
Return windows using the given 'callable' (returning a true or a false
value when invoked with a window name) for descendants of this window.
"""
s = _xwininfo(self.identifier, "tree")
return self._descendants(s, callable)
def name(self):
"Return the name of the window."
d = _xwininfo(self.identifier, "stats")
# Format is 'xwininfo: Window id: <handle> "<name>"
return self._get_this_handle_and_name(d["xwininfo"])[1]
def size(self):
"Return a tuple containing the width and height of this window."
d = _xwininfo(self.identifier, "stats")
return _get_int_properties(d, ["Width", "Height"])
def position(self):
"Return a tuple containing the upper left co-ordinates of this window."
d = _xwininfo(self.identifier, "stats")
return _get_int_properties(d, ["Absolute upper-left X", "Absolute upper-left Y"])
def displayed(self):
"""
Return whether the window is displayed in some way (but not necessarily
visible on the current screen).
"""
d = _xwininfo(self.identifier, "stats")
return d["Map State"] != "IsUnviewable"
def visible(self):
"Return whether the window is displayed and visible."
d = _xwininfo(self.identifier, "stats")
return d["Map State"] == "IsViewable"
def list(desktop=None):
"""
Return a list of windows for the current desktop. If the optional 'desktop'
parameter is specified then attempt to use that particular desktop
environment's mechanisms to look for windows.
"""
root_window = root(desktop)
window_list = [window for window in root_window.descendants() if window.displayed()]
window_list.insert(0, root_window)
return window_list
def root(desktop=None):
"""
Return the root window for the current desktop. If the optional 'desktop'
parameter is specified then attempt to use that particular desktop
environment's mechanisms to look for windows.
"""
# NOTE: The desktop parameter is currently ignored and X11 is tested for
# NOTE: directly.
if _is_x11():
return Window(None)
else:
raise OSError, "Desktop '%s' not supported" % use_desktop(desktop)
def find(callable, desktop=None):
"""
Find and return windows using the given 'callable' for the current desktop.
If the optional 'desktop' parameter is specified then attempt to use that
particular desktop environment's mechanisms to look for windows.
"""
return root(desktop).find(callable)
# vim: tabstop=4 expandtab shiftwidth=4

View File

@@ -0,0 +1,364 @@
html {
margin: 0;
padding: 0; }
body {
background-color: white;
border-radius: 3px;
border: 3px solid #EEE;
box-shadow: inset 0 0 0 1px #CECECE;
font-family: Helvetica,arial,sans-serif;
font-size: 14px;
line-height: 1.6;
width: 975px;
padding: 30px;
margin: 2em auto; }
body > *:first-child {
margin-top: 0 !important; }
body > *:last-child {
margin-bottom: 0 !important; }
a {
color: #4183C4;
text-decoration: none; }
a:hover {
text-decoration: underline; }
a.absent {
color: #cc0000; }
a.anchor {
display: block;
padding-left: 30px;
margin-left: -30px;
cursor: pointer;
position: absolute;
top: 0;
left: 0;
bottom: 0; }
h1, h2, h3, h4, h5, h6 {
margin: 20px 0 10px;
padding: 0;
font-weight: bold;
-webkit-font-smoothing: antialiased;
cursor: text;
position: relative; }
h1:hover a.anchor, h2:hover a.anchor, h3:hover a.anchor, h4:hover a.anchor, h5:hover a.anchor, h6:hover a.anchor {
background: url("../../images/modules/styleguide/para.png") no-repeat 10px center;
text-decoration: none; }
h1 tt, h1 code {
font-size: inherit; }
h2 tt, h2 code {
font-size: inherit; }
h3 tt, h3 code {
font-size: inherit; }
h4 tt, h4 code {
font-size: inherit; }
h5 tt, h5 code {
font-size: inherit; }
h6 tt, h6 code {
font-size: inherit; }
h1 {
font-size: 28px;
color: black; }
h2 {
font-size: 24px;
border-bottom: 1px solid #cccccc;
color: black; }
h3 {
font-size: 18px; }
h4 {
font-size: 16px; }
h5 {
font-size: 14px; }
h6 {
color: #777777;
font-size: 14px; }
p, blockquote, ul, ol, dl, li, table, pre {
margin: 15px 0; }
hr {
background: transparent url("https://a248.e.akamai.net/assets.github.com/assets/primer/markdown/dirty-shade-0e7d81b119cc9beae17b0c98093d121fa0050a74.png") repeat-x 0 0;
border: 0 none;
color: #ccc;
height: 4px;
padding: 0; }
body > h2:first-child {
margin-top: 0;
padding-top: 0; }
body > h1:first-child {
margin-top: 0;
padding-top: 0; }
body > h1:first-child + h2 {
margin-top: 0;
padding-top: 0; }
body > h3:first-child, body > h4:first-child, body > h5:first-child, body > h6:first-child {
margin-top: 0;
padding-top: 0; }
a:first-child h1, a:first-child h2, a:first-child h3, a:first-child h4, a:first-child h5, a:first-child h6 {
margin-top: 0;
padding-top: 0; }
h1 p, h2 p, h3 p, h4 p, h5 p, h6 p {
margin-top: 0; }
li p.first {
display: inline-block; }
ul, ol {
padding-left: 30px; }
ul :first-child, ol :first-child {
margin-top: 0; }
ul :last-child, ol :last-child {
margin-bottom: 0; }
dl {
padding: 0; }
dl dt {
font-size: 14px;
font-weight: bold;
font-style: italic;
padding: 0;
margin: 15px 0 5px; }
dl dt:first-child {
padding: 0; }
dl dt > :first-child {
margin-top: 0; }
dl dt > :last-child {
margin-bottom: 0; }
dl dd {
margin: 0 0 15px;
padding: 0 15px; }
dl dd > :first-child {
margin-top: 0; }
dl dd > :last-child {
margin-bottom: 0; }
blockquote {
border-left: 4px solid #dddddd;
padding: 0 15px;
color: #777777; }
blockquote > :first-child {
margin-top: 0; }
blockquote > :last-child {
margin-bottom: 0; }
table {
border-collapse: collapse; border-spacing: 0; padding: 0; }
table tr {
border-top: 1px solid #cccccc;
background-color: white;
margin: 0;
padding: 0; }
table tr:nth-child(2n) {
background-color: #f8f8f8; }
table tr th {
font-weight: bold;
border: 1px solid #cccccc;
text-align: left;
margin: 0;
padding: 6px 13px; }
table tr td {
border: 1px solid #cccccc;
text-align: left;
margin: 0;
padding: 6px 13px; }
table tr th :first-child, table tr td :first-child {
margin-top: 0; }
table tr th :last-child, table tr td :last-child {
margin-bottom: 0; }
img {
max-width: 100%; }
span.frame {
display: block;
overflow: hidden; }
span.frame > span {
border: 1px solid #dddddd;
display: block;
float: left;
overflow: hidden;
margin: 13px 0 0;
padding: 7px;
width: auto; }
span.frame span img {
display: block;
float: left; }
span.frame span span {
clear: both;
color: #333333;
display: block;
padding: 5px 0 0; }
span.align-center {
display: block;
overflow: hidden;
clear: both; }
span.align-center > span {
display: block;
overflow: hidden;
margin: 13px auto 0;
text-align: center; }
span.align-center span img {
margin: 0 auto;
text-align: center; }
span.align-right {
display: block;
overflow: hidden;
clear: both; }
span.align-right > span {
display: block;
overflow: hidden;
margin: 13px 0 0;
text-align: right; }
span.align-right span img {
margin: 0;
text-align: right; }
span.float-left {
display: block;
margin-right: 13px;
overflow: hidden;
float: left; }
span.float-left span {
margin: 13px 0 0; }
span.float-right {
display: block;
margin-left: 13px;
overflow: hidden;
float: right; }
span.float-right > span {
display: block;
overflow: hidden;
margin: 13px auto 0;
text-align: right; }
code, tt {
margin: 0 2px;
padding: 0 5px;
white-space: nowrap;
border: 1px solid #eaeaea;
background-color: #f8f8f8;
border-radius: 3px; }
pre code {
margin: 0;
padding: 0;
white-space: pre;
border: none;
background: transparent; }
.highlight pre {
background-color: #f8f8f8;
border: 1px solid #cccccc;
font-size: 13px;
line-height: 19px;
overflow: auto;
padding: 6px 10px;
border-radius: 3px; }
pre {
background-color: #f8f8f8;
border: 1px solid #cccccc;
font-size: 13px;
line-height: 19px;
overflow: auto;
padding: 6px 10px;
border-radius: 3px; }
pre code, pre tt {
background-color: transparent;
border: none; }
.markdown-body code,.markdown-body tt{margin:0 2px;padding:0px 5px;white-space:nowrap;border:1px solid #eaeaea;background-color:#f8f8f8;border-radius:3px}
.markdown-body pre>code{margin:0;padding:0;white-space:pre;border:none;background:transparent}
.markdown-body .highlight pre,.markdown-body pre{background-color:#f8f8f8;border:1px solid #ccc;font-size:13px;line-height:19px;overflow:auto;padding:6px 10px;border-radius:3px}
.markdown-body pre code,.markdown-body pre tt{background-color:transparent;border:none}
.highlight{background:#ffffff}
.highlight .c{color:#999988;font-style:italic}
.highlight .err{color:#a61717;background-color:#e3d2d2}
.highlight .k{font-weight:bold}
.highlight .o{font-weight:bold}
.highlight .cm{color:#999988;font-style:italic}
.highlight .cp{color:#999999;font-weight:bold}
.highlight .c1{color:#999988;font-style:italic}
.highlight .cs{color:#999999;font-weight:bold;font-style:italic}
.highlight .gd{color:#000000;background-color:#ffdddd}
.highlight .gd .x{color:#000000;background-color:#ffaaaa}
.highlight .ge{font-style:italic}
.highlight .gr{color:#aa0000}
.highlight .gh{color:#999999}
.highlight .gi{color:#000000;background-color:#ddffdd}
.highlight .gi .x{color:#000000;background-color:#aaffaa}
.highlight .go{color:#888888}
.highlight .gp{color:#555555}
.highlight .gs{font-weight:bold}
.highlight .gu{color:#800080;font-weight:bold}
.highlight .gt{color:#aa0000}
.highlight .kc{font-weight:bold}
.highlight .kd{font-weight:bold}
.highlight .kn{font-weight:bold}
.highlight .kp{font-weight:bold}
.highlight .kr{font-weight:bold}
.highlight .kt{color:#445588;font-weight:bold}
.highlight .m{color:#009999}
.highlight .s{color:#d14}
.highlight .na{color:#008080}
.highlight .nb{color:#0086B3}
.highlight .nc{color:#445588;font-weight:bold}
.highlight .no{color:#008080}
.highlight .ni{color:#800080}
.highlight .ne{color:#990000;font-weight:bold}
.highlight .nf{color:#990000;font-weight:bold}
.highlight .nn{color:#555555}
.highlight .nt{color:#000080}
.highlight .nv{color:#008080}
.highlight .ow{font-weight:bold}
.highlight .w{color:#bbbbbb}
.highlight .mf{color:#009999}
.highlight .mh{color:#009999}
.highlight .mi{color:#009999}
.highlight .mo{color:#009999}
.highlight .sb{color:#d14}
.highlight .sc{color:#d14}
.highlight .sd{color:#d14}
.highlight .s2{color:#d14}
.highlight .se{color:#d14}
.highlight .sh{color:#d14}
.highlight .si{color:#d14}
.highlight .sx{color:#d14}
.highlight .sr{color:#009926}
.highlight .s1{color:#d14}
.highlight .ss{color:#990073}
.highlight .bp{color:#999999}
.highlight .vc{color:#008080}
.highlight .vg{color:#008080}
.highlight .vi{color:#008080}
.highlight .il{color:#009999}
.highlight .gc{color:#999;background-color:#EAF2F5}
.type-csharp .highlight .k{color:#0000FF}
.type-csharp .highlight .kt{color:#0000FF}
.type-csharp .highlight .nf{color:#000000;font-weight:normal}
.type-csharp .highlight .nc{color:#2B91AF}
.type-csharp .highlight .nn{color:#000000}
.type-csharp .highlight .s{color:#A31515}
.type-csharp .highlight .sc{color:#A31515}

View File

@@ -0,0 +1,122 @@
html { font-size: 100%; overflow-y: scroll; -webkit-text-size-adjust: 100%; -ms-text-size-adjust: 100%; }
body{
color:#444;
font-family:Georgia, Palatino, 'Palatino Linotype', Times, 'Times New Roman',
"Hiragino Sans GB", "STXihei", "微软雅黑", serif;
font-size:12px;
line-height:1.5em;
background:#fefefe;
width: 45em;
margin: 10px auto;
padding: 1em;
outline: 1300px solid #FAFAFA;
}
a{ color: #0645ad; text-decoration:none;}
a:visited{ color: #0b0080; }
a:hover{ color: #06e; }
a:active{ color:#faa700; }
a:focus{ outline: thin dotted; }
a:hover, a:active{ outline: 0; }
span.backtick {
border:1px solid #EAEAEA;
border-radius:3px;
background:#F8F8F8;
padding:0 3px 0 3px;
}
::-moz-selection{background:rgba(255,255,0,0.3);color:#000}
::selection{background:rgba(255,255,0,0.3);color:#000}
a::-moz-selection{background:rgba(255,255,0,0.3);color:#0645ad}
a::selection{background:rgba(255,255,0,0.3);color:#0645ad}
p{
margin:1em 0;
}
img{
max-width:100%;
}
h1,h2,h3,h4,h5,h6{
font-weight:normal;
color:#111;
line-height:1em;
}
h4,h5,h6{ font-weight: bold; }
h1{ font-size:2.5em; }
h2{ font-size:2em; border-bottom:1px solid silver; padding-bottom: 5px; }
h3{ font-size:1.5em; }
h4{ font-size:1.2em; }
h5{ font-size:1em; }
h6{ font-size:0.9em; }
blockquote{
color:#666666;
margin:0;
padding-left: 3em;
border-left: 0.5em #EEE solid;
}
hr { display: block; height: 2px; border: 0; border-top: 1px solid #aaa;border-bottom: 1px solid #eee; margin: 1em 0; padding: 0; }
pre , code, kbd, samp {
color: #000;
font-family: monospace;
font-size: 0.88em;
border-radius:3px;
background-color: #F8F8F8;
border: 1px solid #CCC;
}
pre { white-space: pre; white-space: pre-wrap; word-wrap: break-word; padding: 5px 12px;}
pre code { border: 0px !important; padding: 0;}
code { padding: 0 3px 0 3px; }
b, strong { font-weight: bold; }
dfn { font-style: italic; }
ins { background: #ff9; color: #000; text-decoration: none; }
mark { background: #ff0; color: #000; font-style: italic; font-weight: bold; }
sub, sup { font-size: 75%; line-height: 0; position: relative; vertical-align: baseline; }
sup { top: -0.5em; }
sub { bottom: -0.25em; }
ul, ol { margin: 1em 0; padding: 0 0 0 2em; }
li p:last-child { margin:0 }
dd { margin: 0 0 0 2em; }
img { border: 0; -ms-interpolation-mode: bicubic; vertical-align: middle; }
table { border-collapse: collapse; border-spacing: 0; }
td { vertical-align: top; }
@media only screen and (min-width: 480px) {
body{font-size:14px;}
}
@media only screen and (min-width: 768px) {
body{font-size:16px;}
}
@media print {
* { background: transparent !important; color: black !important; filter:none !important; -ms-filter: none !important; }
body{font-size:12pt; max-width:100%; outline:none;}
a, a:visited { text-decoration: underline; }
hr { height: 1px; border:0; border-bottom:1px solid black; }
a[href]:after { content: " (" attr(href) ")"; }
abbr[title]:after { content: " (" attr(title) ")"; }
.ir a:after, a[href^="javascript:"]:after, a[href^="#"]:after { content: ""; }
pre, blockquote { border: 1px solid #999; padding-right: 1em; page-break-inside: avoid; }
tr, img { page-break-inside: avoid; }
img { max-width: 100% !important; }
@page :left { margin: 15mm 20mm 15mm 10mm; }
@page :right { margin: 15mm 10mm 15mm 20mm; }
p, h2, h3 { orphans: 3; widows: 3; }
h2, h3 { page-break-after: avoid; }
}

View File

@@ -0,0 +1 @@
{"url": "https://github.com/revolunet/sublimetext-markdown-preview", "version": "2013.04.01.18.50.45", "description": "markdown preview plugin for sublime text 2"}

View File

@@ -0,0 +1,141 @@
<h1 id="sample-markdown-cheat-sheet">Sample Markdown Cheat Sheet</h1>
<p>This is a sample markdown file to help you write Markdown quickly :)</p>
<p>If you use the fabulous <a href="http://sublimetext.com">Sublime Text 2 editor</a> along with the <a href="https://github.com/revolunet/sublimetext-markdown-preview">Markdown Preview plugin</a>, open your ST2 Palette with <code>CMD+P</code> then choose <code>Markdown Preview in browser</code> to see the result in your browser.</p>
<h2 id="text-basics">Text basics</h2>
<p>this is <em>italic</em> and this is <strong>bold</strong> . another <em>italic</em> and another <strong>bold</strong></p>
<p>this is <code>important</code> text. and percentage signs : % and <code>%</code></p>
<p>This is a paragraph with a footnote (builtin parser only). <sup class="footnote-ref" id="fnref-note-id"><a href="#fn-note-id">1</a></sup> </p>
<p>Insert <code>[ toc ]</code> without spaces to generate a table of contents (builtin parser only).</p>
<h2 id="indentation">Indentation</h2>
<blockquote>
<p>Here is some indented text</p>
<blockquote>
<p>even more indented</p>
</blockquote>
</blockquote>
<h2 id="titles">Titles</h2>
<h1 id="big-title-h1">Big title (h1)</h1>
<h2 id="middle-title-h2">Middle title (h2)</h2>
<h3 id="smaller-title-h3">Smaller title (h3)</h3>
<h4 id="and-so-on-hx">and so on (hX)</h4>
<h5 id="and-so-on-hx-2">and so on (hX)</h5>
<h6 id="and-so-on-hx-3">and so on (hX)</h6>
<h2 id="example-lists-1">Example lists (1)</h2>
<ul>
<li>bullets can be <code>-</code>, <code>+</code>, or <code>*</code></li>
<li>bullet list 1</li>
<li><p>bullet list 2</p>
<ul>
<li>sub item 1</li>
<li><p>sub item 2</p>
<p>with indented text inside</p></li>
</ul></li>
<li><p>bullet list 3</p></li>
<li>bullet list 4</li>
<li>bullet list 5</li>
</ul>
<h2 id="links">Links</h2>
<p>This is an <a href="http://lmgtfy.com/">example inline link</a> and <a href="http://lmgtfy.com/" title="Hello, world">another one with a title</a>.</p>
<p>Links can also be reference based : <a href="http://revolunet.com">reference 1</a> or <a href="http://revolunet.com" title="rich web apps">reference 2 with title</a>.</p>
<p>References are usually placed at the bottom of the document</p>
<h2 id="images">Images</h2>
<p>A sample image :</p>
<p><img src="http://www.revolunet.com/static/parisjs8/img/logo-revolunet-carre.jpg" alt="revolunet logo" title="revolunet logo" /></p>
<p>As links, images can also use references instead of inline links :</p>
<p><img src="http://www.revolunet.com/static/parisjs8/img/logo-revolunet-carre.jpg" alt="revolunet logo" title="revolunet logo" /></p>
<h2 id="code">Code</h2>
<p>It's quite easy to show code in markdown files.</p>
<p>Backticks can be used to <code>highlight</code> some words.</p>
<p>Also, any indented block is considered a code block.</p>
<pre><code>&lt;script&gt;
document.location = 'http://lmgtfy.com/?q=markdown+cheat+sheet';
&lt;/script&gt;
</code></pre>
<h2 id="github-flavored-markdown">GitHub Flavored Markdown</h2>
<p>If you use the Github parser, you can use some of <a href="http://github.github.com/github-flavored-markdown/">Github Flavored Markdown</a> syntax :</p>
<ul>
<li>User/Project@SHA: revolunet/sublimetext-markdown-preview@7da61badeda468b5019869d11000307e07e07401</li>
<li>User/Project#Issue: revolunet/sublimetext-markdown-preview#1</li>
<li>User : @revolunet</li>
</ul>
<p>Some Python code :</p>
<pre><code>import random
class CardGame(object):
""" a sample python class """
NB_CARDS = 32
def __init__(self, cards=5):
self.cards = random.sample(range(self.NB_CARDS), 5)
print 'ready to play'
</code></pre>
<p>Some Javascript code :</p>
<pre><code>var config = {
duration: 5,
comment: 'WTF'
}
// callbacks beauty un action
async_call('/path/to/api', function(json) {
another_call(json, function(result2) {
another_another_call(result2, function(result3) {
another_another_another_call(result3, function(result4) {
alert('And if all went well, i got my result :)');
});
});
});
})
</code></pre>
<h2 id="about">About</h2>
<p>This plugin and this sample file is proudly brought to you by the <a href="http://revolunet.com">revolunet team</a></p>
<div class="footnotes">
<hr />
<ol>
<li id="fn-note-id">
<p>This is the text of the note.&nbsp;<a href="#fnref-note-id" class="footnoteBackLink" title="Jump back to footnote 1 in the text.">&#8617;</a></p>
</li>
</ol>
</div>

View File

@@ -0,0 +1,132 @@
Sample Markdown Cheat Sheet
===========================
This is a sample markdown file to help you write Markdown quickly :)
If you use the fabulous [Sublime Text 2 editor][ST2] along with the [Markdown Preview plugin][MarkdownPreview], open your ST2 Palette with `CMD+P` then choose `Markdown Preview in browser` to see the result in your browser.
## Text basics
this is *italic* and this is **bold** . another _italic_ and another __bold__
this is `important` text. and percentage signs : % and `%`
This is a paragraph with a footnote (builtin parser only). [^note-id]
Insert `[ toc ]` without spaces to generate a table of contents (builtin parser only).
## Indentation
> Here is some indented text
>> even more indented
## Titles
# Big title (h1)
## Middle title (h2)
### Smaller title (h3)
#### and so on (hX)
##### and so on (hX)
###### and so on (hX)
## Example lists (1)
- bullets can be `-`, `+`, or `*`
- bullet list 1
- bullet list 2
- sub item 1
- sub item 2
with indented text inside
- bullet list 3
+ bullet list 4
* bullet list 5
## Links
This is an [example inline link](http://lmgtfy.com/) and [another one with a title](http://lmgtfy.com/ "Hello, world").
Links can also be reference based : [reference 1][ref1] or [reference 2 with title][ref2].
References are usually placed at the bottom of the document
## Images
A sample image :
![revolunet logo](http://www.revolunet.com/static/parisjs8/img/logo-revolunet-carre.jpg "revolunet logo")
As links, images can also use references instead of inline links :
![revolunet logo][revolunet-logo]
## Code
It's quite easy to show code in markdown files.
Backticks can be used to `highlight` some words.
Also, any indented block is considered a code block.
<script>
document.location = 'http://lmgtfy.com/?q=markdown+cheat+sheet';
</script>
## GitHub Flavored Markdown
If you use the Github parser, you can use some of [Github Flavored Markdown][gfm] syntax :
* User/Project@SHA: revolunet/sublimetext-markdown-preview@7da61badeda468b5019869d11000307e07e07401
* User/Project#Issue: revolunet/sublimetext-markdown-preview#1
* User : @revolunet
Some Python code :
```python
import random
class CardGame(object):
""" a sample python class """
NB_CARDS = 32
def __init__(self, cards=5):
self.cards = random.sample(range(self.NB_CARDS), 5)
print 'ready to play'
```
Some Javascript code :
```js
var config = {
duration: 5,
comment: 'WTF'
}
// callbacks beauty un action
async_call('/path/to/api', function(json) {
another_call(json, function(result2) {
another_another_call(result2, function(result3) {
another_another_another_call(result3, function(result4) {
alert('And if all went well, i got my result :)');
});
});
});
})
```
The Github Markdown also brings some [nice Emoji support][emoji] : :+1: :heart: :beer:
[^note-id]: This is the text of the note.
## About
This plugin and this sample file is proudly brought to you by the [revolunet team][revolunet]
[ref1]: http://revolunet.com
[ref2]: http://revolunet.com "rich web apps"
[MarkdownREF]: http://daringfireball.net/projects/markdown/basics
[MarkdownPreview]: https://github.com/revolunet/sublimetext-markdown-preview
[ST2]: http://sublimetext.com
[revolunet]: http://revolunet.com
[revolunet-logo]: http://www.revolunet.com/static/parisjs8/img/logo-revolunet-carre.jpg "revolunet logo"
[gfm]: http://github.github.com/github-flavored-markdown/
[emoji]: http://www.emoji-cheat-sheet.com/