github-markdown-server 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 5f1f3e1b6c0b783128c49522e43ed9a0adad443c
4
+ data.tar.gz: 9b81373d11efa51e007e87e495ad1a65fecc640a
5
+ SHA512:
6
+ metadata.gz: 6c6de876abe5323c3fcb788827e2a76c9c244da3afa336ea5fdb649c5aeaee12bb28dec649a43563ed95df8724f3c733c27a7228631ca016eb63b3c01e884b95
7
+ data.tar.gz: a998e171e149d42f06941a553335791c7faeb70f20570616e61f87f18c7863678d12f3c36d3d1dd977ce3d8df18b968814e8d73f6e46a8e24ac143c51fb1b0f9
data/.gitignore ADDED
@@ -0,0 +1 @@
1
+ *.gem
data/LICENSE ADDED
@@ -0,0 +1,22 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2014 ark
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
22
+
data/README.md ADDED
@@ -0,0 +1,24 @@
1
+ # Github Markdown Server
2
+
3
+ Use your favorite editor to edit a markdown file, Run the server and open the file.
4
+ Saving in your editor updates instantly in the browser.
5
+
6
+ github-markdown-server is built on top of [github-markdown-preview](https://github.com/dmarcotte/github-markdown-preview).
7
+
8
+ ## Usage
9
+
10
+ ```shell
11
+ github-markdown-server README.md
12
+ ```
13
+
14
+ This will start a server serving in the current directory and all child directories and open a browser (on a mac) showing README.md converted to html. If you navigate to a directory name only child directories and .md files are shown in a directory listing. If there is a README.md file in that directory it will be appended to the directory listing.
15
+
16
+ ## Contrib
17
+
18
+ There is a [contrib](contrib/) directory with an emacs lisp file which will start a server and open a file for you. It'll keep track of which servers it has started and reuse an existing server if a file you want to preview is under that server's serving directory.
19
+
20
+ There is also a small python script (called `p`) which will work with files and produce paths and urls.
21
+
22
+ ## Contributing
23
+
24
+ Please feel free to send me pull requests! This is my first Ruby project and it always feels like my first time when I write Emacs Lisp.
@@ -0,0 +1,51 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ $LOAD_PATH.unshift("#{File.dirname(File.dirname(__FILE__))}/lib")
4
+
5
+ require 'github-markdown-server'
6
+ require 'optparse'
7
+
8
+ comment_mode = false
9
+ server_port = 8000
10
+ browser = true
11
+ directory = nil
12
+ opt_parser = OptionParser.new do |opt|
13
+ opt.banner = "Usage: github-markdown-server DIRECTORY"
14
+ opt.separator ""
15
+ opt.separator "Options"
16
+
17
+ opt.on("-b", "--[no-]browser", "don't open initial file in browser when you start a server") do |b|
18
+ browser = b
19
+ end
20
+
21
+ opt.on("-c", "--comment-mode", "renders a preview for Github comments/issues") do
22
+ comment_mode = true
23
+ end
24
+
25
+ opt.on("-d=", "--directory=", "start webserver listening on this port") do |dir|
26
+ directory = dir
27
+ end
28
+
29
+ opt.on("-p=", "--port=", "start webserver listening on this port") do |port|
30
+ server_port = port unless port.nil?
31
+ end
32
+
33
+ opt.on("-v", "--version", "print the version") do
34
+ $stdout.puts 'github-markdown-server version ' + GithubMarkdownServer::VERSION
35
+ Kernel.exit
36
+ end
37
+ end
38
+
39
+ opt_parser.parse!
40
+
41
+ file_name = ARGV.at(0) || '.'
42
+ directory = directory || file_name
43
+ options = {
44
+ :comment_mode => comment_mode,
45
+ :server_port => server_port,
46
+ :browser => browser,
47
+ :directory => directory,
48
+ :file_name => file_name,
49
+ }
50
+ p "go on #{server_port}"
51
+ GithubMarkdownServer::Server.new(options)
@@ -0,0 +1,73 @@
1
+ ;;; github-markdown-server -- start a server and open a markdown file in it
2
+ ;;; Created by: Alex K (wtwf.com) Thu Nov 27 02:48:00 2014
3
+
4
+ ;;; Commentary:
5
+
6
+ ;;; Code:
7
+
8
+ (require 'cl-lib)
9
+
10
+ (defvar github-markdown-servers '() "The servers we have running.")
11
+ (defvar github-markdown-server-port 7494 "The next available server port.")
12
+
13
+ (defun git-base (&optional file-name)
14
+ "Get the base of a git repository for FILE-NAME (or the current buffer)."
15
+ (interactive (buffer-file-name))
16
+ (shell-command-to-string (concat "p -t -g " (shell-quote-argument buffer-file-name))))
17
+
18
+ (defun github-markdown-serve (&optional file-name)
19
+ "Get the base of a git repository for FILE-NAME (or the current buffer)."
20
+ (interactive (list (buffer-file-name)))
21
+ (let ((base (git-base file-name)) (server nil) (server-running nil))
22
+ ;;;
23
+ (progn
24
+ (if (< (length base) 1) (setq base (directory-file-name file-name)))
25
+ ;; find a server that might still be running
26
+ (setq server (cl-reduce (lambda (a b)
27
+ (if (and (string= (car b) (substring base 0 (length (car b))))
28
+ (or (not (car a)) (< (length (car b)) (length (car a)))))
29
+ b a)) (cons nil github-markdown-servers)))
30
+ (if (and server
31
+ (progn
32
+ (message (concat "Checking if server running at" (prin1-to-string server)))
33
+ (setq server-running
34
+ (shell-command-to-string
35
+ (concat "lsof -n -i4TCP:" (number-to-string (cdr server)) " | grep LISTEN")))
36
+ (> (length server-running) 0)))
37
+ (progn
38
+ (message "reusing server")
39
+ (call-process-shell-command
40
+ (concat "open "
41
+ (shell-quote-argument
42
+ (concat "http://localhost:"
43
+ (number-to-string (cdr server))
44
+ (substring file-name (length (car server))))))))
45
+ (progn
46
+ (if server
47
+ (progn (message (concat "re-starting server on port " (number-to-string (cdr server)))))
48
+ (progn
49
+ (message "starting server"))
50
+ (setq server (cons base github-markdown-server-port))
51
+ ))
52
+ (call-process-shell-command (concat "github-markdown-server"
53
+ " --directory=" (shell-quote-argument (car server))
54
+ " --port=" (number-to-string (cdr server))
55
+ " " (shell-quote-argument file-name)) nil 0)
56
+ (if (not server)
57
+ (progn (add-to-list 'github-markdown-servers server)
58
+ (setq github-markdown-server-port (+ github-markdown-server-port 1))))))))
59
+
60
+ (defun view-file-in-browser (&optional file-name)
61
+ "Open up file on github or via a local markdown server.
62
+ FILE-NAME will be current buffer if not specified.
63
+ Prefix arg \[universal-argument] to not run local server."
64
+ (interactive (list (buffer-file-name)))
65
+ (if (and (not current-prefix-arg) (string-match "\.md$" file-name))
66
+ (github-markdown-serve file-name)
67
+ (call-process-shell-command
68
+ (concat "open "
69
+ (shell-quote-argument
70
+ (shell-command-to-string (concat "p -u -t " (shell-quote-argument file-name))))) nil 0)))
71
+
72
+ (provide 'github-markdown-server)
73
+ ;;; github-markdown-server ends here
data/contrib/p ADDED
@@ -0,0 +1,116 @@
1
+ #!/usr/bin/python
2
+ # Created by: Alex K (wtwf.com)Tue Dec 7 16:50:41 2004
3
+ # Last Modified: Time-stamp: <Thu Nov 27 03:08:53 PST 2014>
4
+
5
+ """
6
+ Turn a path into an absolute path or url.
7
+
8
+ -g, --git print out the root directory of this git repository
9
+ -h, --help print out this message
10
+ -p, --path show a full absolute path to the file
11
+ -t, --trim do not append a newline to the file
12
+ -u, --url show a url to the file (https://github.com/... or file:///)
13
+ -s, --server show a utl to a local github-markdown-server
14
+ --port use this port for github-markdown-server url (default 7474)
15
+ --host use this host for github-markdown-server url (default localhost)
16
+ """
17
+
18
+ __author__ = 'wtwf.com (Alex K)'
19
+
20
+ import getopt
21
+ import logging
22
+ import os
23
+ import re
24
+ import sys
25
+
26
+ def Usage(code, msg=''):
27
+ """Show a usage message."""
28
+ if code:
29
+ fd = sys.stderr
30
+ else:
31
+ fd = sys.stdout
32
+ PROGRAM = os.path.basename(sys.argv[0]) # pylint: disable=invalid-name,unused-variable
33
+ print >> fd, __doc__ % locals()
34
+ if msg:
35
+ print >> fd, msg
36
+ sys.exit(code)
37
+
38
+ def Main():
39
+ """Run."""
40
+ logging.basicConfig()
41
+ logging.getLogger().setLevel(logging.DEBUG)
42
+ try:
43
+ opts, args = getopt.getopt(sys.argv[1:], 'ghpstu',
44
+ 'git,help,host=,path,port=,server,trim,url'.split(','))
45
+ except getopt.error, msg:
46
+ Usage(1, msg)
47
+
48
+ if not args:
49
+ Usage(1)
50
+
51
+ output = 'path'
52
+ trim = False
53
+ port = 7474
54
+ host = 'localhost'
55
+ for opt, arg in opts:
56
+ if opt in ('-g', '--git'):
57
+ output = 'git'
58
+ if opt in ('-h', '--help'):
59
+ Usage(0)
60
+ if opt in ('--host',):
61
+ host = arg
62
+ if opt in ('-p', '--path'):
63
+ output = 'path'
64
+ if opt in ('--port',):
65
+ port = int(arg)
66
+ if opt in ('-s', '--server'):
67
+ output = 'github-markdown-server'
68
+ if opt in ('-t', '--trim'):
69
+ trim = True
70
+ if opt in ('-u', '--url'):
71
+ output = 'url'
72
+
73
+ for arg in args:
74
+ arg = os.path.abspath(arg)
75
+ if output != 'path':
76
+ arg = ConvertToUrl(arg, output, port, host)
77
+ if trim:
78
+ sys.stdout.write(arg) # for python 3 we could do print(arg, end='',flush=True)
79
+ else:
80
+ print arg
81
+
82
+ def ConvertToUrl(arg, output, port, host):
83
+ """Try to turn this into a url."""
84
+ directory = arg
85
+ base_url = None
86
+ while directory != '/' and not base_url:
87
+ directory = os.path.dirname(directory)
88
+ config_filename = os.path.join(directory, '.git', 'config')
89
+ if os.path.exists(config_filename):
90
+ if output == 'git':
91
+ return directory
92
+ for line in open(config_filename):
93
+ match = re.search(r'url = git@github.com:(.*)\.git', line)
94
+ if match:
95
+ base_url = 'https://github.com/%s/blob/master/' % match.group(1)
96
+ break
97
+
98
+ if output == 'git':
99
+ return ''
100
+ if output == 'github-markdown-server':
101
+ if base_url:
102
+ basename = arg[len(directory) + 1:]
103
+ arg = 'http://%s:%d/%s' % (host, port, basename)
104
+ else:
105
+ basename = os.path.basename(arg)
106
+ arg = 'http://%s:%d/%s' % (host, port, basename)
107
+ else:
108
+ if base_url:
109
+ arg = base_url + arg[len(directory) + 1:]
110
+ else:
111
+ arg = 'file://' + arg
112
+
113
+ return arg
114
+
115
+ if __name__ == '__main__':
116
+ Main()
Binary file
data/data/js/live.js ADDED
@@ -0,0 +1,233 @@
1
+ /*
2
+ Live.js - One script closer to Designing in the Browser
3
+ Written for Handcraft.com by Martin Kool (@mrtnkl).
4
+
5
+ Version 4.
6
+ Recent change: Made stylesheet and mimetype checks case insensitive.
7
+
8
+ http://livejs.com
9
+ http://livejs.com/license (MIT)
10
+ @livejs
11
+
12
+ Include live.js#css to monitor css changes only.
13
+ Include live.js#js to monitor js changes only.
14
+ Include live.js#html to monitor html changes only.
15
+ Mix and match to monitor a preferred combination such as live.js#html,css
16
+
17
+ By default, just include live.js to monitor all css, js and html changes.
18
+
19
+ Live.js can also be loaded as a bookmarklet. It is best to only use it for CSS then,
20
+ as a page reload due to a change in html or css would not re-include the bookmarklet.
21
+ To monitor CSS and be notified that it has loaded, include it as: live.js#css,notify
22
+ */
23
+ (function () {
24
+
25
+ var headers = { "Etag": 1, "Last-Modified": 1, "Content-Length": 1, "Content-Type": 1 },
26
+ resources = {},
27
+ pendingRequests = {},
28
+ currentLinkElements = {},
29
+ oldLinkElements = {},
30
+ interval = 1000,
31
+ loaded = false,
32
+ active = { "html": 1, "css": 1, "js": 1 };
33
+
34
+ var Live = {
35
+
36
+ // performs a cycle per interval
37
+ heartbeat: function () {
38
+ if (document.body) {
39
+ // make sure all resources are loaded on first activation
40
+ if (!loaded) Live.loadresources();
41
+ Live.checkForChanges();
42
+ }
43
+ setTimeout(Live.heartbeat, interval);
44
+ },
45
+
46
+ // loads all local css and js resources upon first activation
47
+ loadresources: function () {
48
+
49
+ // helper method to assert if a given url is local
50
+ function isLocal(url) {
51
+ var loc = document.location,
52
+ reg = new RegExp("^\\.|^\/(?!\/)|^[\\w]((?!://).)*$|" + loc.protocol + "//" + loc.host);
53
+ return url.match(reg);
54
+ }
55
+
56
+ // gather all resources
57
+ var scripts = document.getElementsByTagName("script"),
58
+ links = document.getElementsByTagName("link"),
59
+ uris = [];
60
+
61
+ // track local js urls
62
+ for (var i = 0; i < scripts.length; i++) {
63
+ var script = scripts[i], src = script.getAttribute("src");
64
+ if (src && isLocal(src))
65
+ uris.push(src);
66
+ if (src && src.match(/\blive.js#/)) {
67
+ for (var type in active)
68
+ active[type] = src.match("[#,|]" + type) != null
69
+ if (src.match("notify"))
70
+ alert("Live.js is loaded.");
71
+ }
72
+ }
73
+ if (!active.js) uris = [];
74
+ if (active.html) uris.push(document.location.href);
75
+
76
+ // track local css urls
77
+ for (var i = 0; i < links.length && active.css; i++) {
78
+ var link = links[i], rel = link.getAttribute("rel"), href = link.getAttribute("href", 2);
79
+ if (href && rel && rel.match(new RegExp("stylesheet", "i")) && isLocal(href)) {
80
+ uris.push(href);
81
+ currentLinkElements[href] = link;
82
+ }
83
+ }
84
+
85
+ // initialize the resources info
86
+ for (var i = 0; i < uris.length; i++) {
87
+ var url = uris[i];
88
+ Live.getHead(url, function (url, info) {
89
+ resources[url] = info;
90
+ });
91
+ }
92
+
93
+ // add rule for morphing between old and new css files
94
+ var head = document.getElementsByTagName("head")[0],
95
+ style = document.createElement("style"),
96
+ rule = "transition: all .3s ease-out;"
97
+ css = [".livejs-loading * { ", rule, " -webkit-", rule, "-moz-", rule, "-o-", rule, "}"].join('');
98
+ style.setAttribute("type", "text/css");
99
+ head.appendChild(style);
100
+ style.styleSheet ? style.styleSheet.cssText = css : style.appendChild(document.createTextNode(css));
101
+
102
+ // yep
103
+ loaded = true;
104
+ },
105
+
106
+ // check all tracking resources for changes
107
+ checkForChanges: function () {
108
+ for (var url in resources) {
109
+ if (pendingRequests[url])
110
+ continue;
111
+
112
+ Live.getHead(url, function (url, newInfo) {
113
+ var oldInfo = resources[url],
114
+ hasChanged = false;
115
+ resources[url] = newInfo;
116
+ for (var header in oldInfo) {
117
+ // do verification based on the header type
118
+ var oldValue = oldInfo[header],
119
+ newValue = newInfo[header],
120
+ contentType = newInfo["Content-Type"];
121
+ switch (header.toLowerCase()) {
122
+ case "etag":
123
+ if (!newValue) break;
124
+ // fall through to default
125
+ default:
126
+ hasChanged = oldValue != newValue;
127
+ break;
128
+ }
129
+ // if changed, act
130
+ if (hasChanged) {
131
+ Live.refreshResource(url, contentType);
132
+ break;
133
+ }
134
+ }
135
+ });
136
+ }
137
+ },
138
+
139
+ // act upon a changed url of certain content type
140
+ refreshResource: function (url, type) {
141
+ switch (type.toLowerCase()) {
142
+ // css files can be reloaded dynamically by replacing the link element
143
+ case "text/css":
144
+ var link = currentLinkElements[url],
145
+ html = document.body.parentNode,
146
+ head = link.parentNode,
147
+ next = link.nextSibling,
148
+ newLink = document.createElement("link");
149
+
150
+ html.className = html.className.replace(/\s*livejs\-loading/gi, '') + ' livejs-loading';
151
+ newLink.setAttribute("type", "text/css");
152
+ newLink.setAttribute("rel", "stylesheet");
153
+ newLink.setAttribute("href", url + "?now=" + new Date() * 1);
154
+ next ? head.insertBefore(newLink, next) : head.appendChild(newLink);
155
+ currentLinkElements[url] = newLink;
156
+ oldLinkElements[url] = link;
157
+
158
+ // schedule removal of the old link
159
+ Live.removeoldLinkElements();
160
+ break;
161
+
162
+ // check if an html resource is our current url, then reload
163
+ case "text/html":
164
+ if (url != document.location.href)
165
+ return;
166
+
167
+ // local javascript changes cause a reload as well
168
+ case "text/javascript":
169
+ case "application/javascript":
170
+ case "application/x-javascript":
171
+ document.location.reload();
172
+ }
173
+ },
174
+
175
+ // removes the old stylesheet rules only once the new one has finished loading
176
+ removeoldLinkElements: function () {
177
+ var pending = 0;
178
+ for (var url in oldLinkElements) {
179
+ // if this sheet has any cssRules, delete the old link
180
+ try {
181
+ var link = currentLinkElements[url],
182
+ oldLink = oldLinkElements[url],
183
+ html = document.body.parentNode,
184
+ sheet = link.sheet || link.styleSheet,
185
+ rules = sheet.rules || sheet.cssRules;
186
+ if (rules.length >= 0) {
187
+ oldLink.parentNode.removeChild(oldLink);
188
+ delete oldLinkElements[url];
189
+ setTimeout(function () {
190
+ html.className = html.className.replace(/\s*livejs\-loading/gi, '');
191
+ }, 100);
192
+ }
193
+ } catch (e) {
194
+ pending++;
195
+ }
196
+ if (pending) setTimeout(Live.removeoldLinkElements, 50);
197
+ }
198
+ },
199
+
200
+ // performs a HEAD request and passes the header info to the given callback
201
+ getHead: function (url, callback) {
202
+ pendingRequests[url] = true;
203
+ var xhr = window.XMLHttpRequest ? new XMLHttpRequest() : new ActiveXObject("Microsoft.XmlHttp");
204
+ xhr.open("HEAD", url, true);
205
+ xhr.onreadystatechange = function () {
206
+ delete pendingRequests[url];
207
+ if (xhr.readyState == 4 && xhr.status != 304) {
208
+ xhr.getAllResponseHeaders();
209
+ var info = {};
210
+ for (var h in headers) {
211
+ var value = xhr.getResponseHeader(h);
212
+ // adjust the simple Etag variant to match on its significant part
213
+ if (h.toLowerCase() == "etag" && value) value = value.replace(/^W\//, '');
214
+ if (h.toLowerCase() == "content-type" && value) value = value.replace(/^(.*?);.*?$/i, "$1");
215
+ info[h] = value;
216
+ }
217
+ callback(url, info);
218
+ }
219
+ }
220
+ xhr.send();
221
+ }
222
+ };
223
+
224
+ // start listening
225
+ if (document.location.protocol != "file:") {
226
+ if (!window.liveJsLoaded)
227
+ Live.heartbeat();
228
+
229
+ window.liveJsLoaded = true;
230
+ }
231
+ else if (window.console)
232
+ console.log("Live.js doesn't support the file protocol. It needs http.");
233
+ })();
@@ -0,0 +1,25 @@
1
+ $:.push File.expand_path('../lib', __FILE__)
2
+ require 'github-markdown-server'
3
+
4
+ Gem::Specification.new do |s|
5
+ s.name = 'github-markdown-server'
6
+ s.version = GithubMarkdownServer::VERSION
7
+ s.platform = Gem::Platform::RUBY
8
+ s.authors = ['Alex K (wtwf.com)']
9
+ s.email = 'ruby@mail.wtwf.com'
10
+ s.homepage = 'https://github.com/arkarkark/github-markdown-server'
11
+ s.summary = %q{Use your favorite editor to edit a markdown file, Run the server and open the file. Saving in your editor updates instantly in the browser.}
12
+ s.description = %q{Runs a webserver to preview Github markdown with live.js updating.}
13
+ s.license = 'MIT'
14
+
15
+ s.add_dependency 'github-markdown-preview', '~> 3.1', '>= 3.1.3'
16
+
17
+ s.add_development_dependency 'minitest', '~> 5.4'
18
+ s.add_development_dependency 'bundler', '~> 1.7'
19
+ s.add_development_dependency 'rake', '~> 10.3'
20
+
21
+ s.files = `git ls-files`.split("\n")
22
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
23
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
24
+ s.require_paths = %w(lib)
25
+ end
@@ -0,0 +1,7 @@
1
+ module GithubMarkdownServer
2
+ class FileNotFoundError < StandardError; end
3
+
4
+ require 'github-markdown-server/version'
5
+ require 'github-markdown-server/resources'
6
+ require 'github-markdown-server/server'
7
+ end
@@ -0,0 +1,9 @@
1
+ module GithubMarkdownServer
2
+ class Resources
3
+ ##
4
+ # Transforms a resource_path in data/ into an absolute path
5
+ def self.expand_path(resource_path)
6
+ File.join(File.dirname(File.expand_path(__FILE__)), '..', '..', 'data', resource_path)
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,136 @@
1
+ require 'github-markdown-preview'
2
+ require 'pathname'
3
+ require 'tempfile'
4
+ require 'webrick'
5
+
6
+
7
+ module GithubMarkdownServer
8
+
9
+ ##
10
+ # Serves files and converts markdown to github like html (with live.js as well).
11
+ class Server
12
+ def initialize(options = {})
13
+ port = options[:server_port] || 8000
14
+ @directory = File.expand_path(options[:directory])
15
+ @file_name = File.expand_path(options[:file_name])
16
+ url = "http://localhost:#{port}/"
17
+
18
+ if !File.directory?(@directory)
19
+ @directory = File.dirname(@directory)
20
+ end
21
+
22
+ url += @file_name[@directory.length + 1..-1]
23
+
24
+ server_options = {
25
+ :Port => port,
26
+ :DocumentRoot => @directory,
27
+ Logger: WEBrick::Log.new("/dev/null"),
28
+ AccessLog: [],
29
+ }
30
+ if options[:browser]
31
+ server_options[:StartCallback] = Proc.new {
32
+ system('open', url)
33
+ }
34
+ end
35
+ server = WEBrick::HTTPServer.new(server_options)
36
+
37
+ trap 'INT' do server.shutdown end
38
+ server.mount_proc '/' do |req, res|
39
+ if req.path == '/favicon.ico'
40
+ source_file = Resources.expand_path(File.join('image','favicon.ico'))
41
+ else
42
+ source_file = File.join(@directory, req.path)
43
+ end
44
+ case req.request_method
45
+ when 'HEAD'
46
+ res['last-modified'] = File.mtime(source_file).to_s
47
+ else
48
+ livejs = "<script>\n#{IO.read(Resources.expand_path(File.join('js','live.js')))}\n</script>"
49
+
50
+ if source_file.end_with? '.md'
51
+ res.body = md2html(source_file)
52
+ res.body += livejs
53
+ elsif File.directory?(source_file)
54
+ directory = source_file
55
+ for index in ['index.md', 'index.html', 'index.htm']
56
+ source_file = File.join(directory, index)
57
+ if File.exists?(source_file)
58
+ res.body = IO.read(source_file)
59
+ res.body += livejs
60
+ break
61
+ end
62
+ end
63
+ if !File.exists?(source_file)
64
+ bonus = nil
65
+ readme = File.join(directory, '/README.md')
66
+ if File.exists?(readme)
67
+ bonus = md2html(readme)
68
+ else
69
+ bonus = emptystyles
70
+ end
71
+ res.body = directory_listing(directory, req.path == '/', bonus)
72
+ end
73
+ else
74
+ res.body = IO.read(source_file)
75
+ end
76
+ end
77
+ res['content-type'] = mime_type(File.extname(source_file))
78
+ end
79
+
80
+ puts "Starting server #{url}"
81
+ server.start
82
+ end
83
+
84
+
85
+ def md2html(file)
86
+ out = Tempfile.new(File.basename(file))
87
+ GithubMarkdownPreview::HtmlPreview.new(file, {:preview_file => out.path})
88
+ IO.read(out.path)
89
+ end
90
+
91
+ def emptystyles
92
+ file = Tempfile.new('')
93
+ out = Tempfile.new('')
94
+ GithubMarkdownPreview::HtmlPreview.new(file, {:preview_file => out.path}).wrap_preview('')
95
+ end
96
+
97
+ def directory_listing(dir, root, bonus)
98
+ body = '<ul>'
99
+ body += '<li><a href="../">..</a>' unless root
100
+ dirs = Pathname.glob(File.join(dir, '/*/')).map do |x|
101
+ d = x.basename.to_s
102
+ "<li><a href=\"#{d}/\">#{d}</a></li>"
103
+ end
104
+ mds = Pathname.glob(File.join(dir, '*.md')).map do |x|
105
+ md = x.basename.to_s
106
+ "<li><a href=\"#{md}\">#{md}</a></li>"
107
+ end
108
+
109
+ body += dirs.join('') unless dirs.empty?
110
+ body += mds.join('') unless mds.empty?
111
+
112
+ body += '</ul>'
113
+ if bonus
114
+ sep = '<div class="readme-content">'
115
+ body = bonus.sub!(sep, (body + sep))
116
+ end
117
+ body
118
+ end
119
+
120
+ def mime_type(ext)
121
+ ext = ext.downcase.sub(/^\./, '')
122
+ case ext
123
+ when 'gif', 'jpg', 'png'
124
+ "image/#{ext}"
125
+ when 'md', 'html', 'htm'
126
+ 'text/html'
127
+ when 'js', 'css'
128
+ "text/#{ext}"
129
+ when 'ico'
130
+ 'image/vnd.microsoft.icon'
131
+ else
132
+ 'application/octet-stream'
133
+ end
134
+ end
135
+ end
136
+ end
@@ -0,0 +1,3 @@
1
+ module GithubMarkdownServer
2
+ VERSION = '0.0.1'
3
+ end
metadata ADDED
@@ -0,0 +1,120 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: github-markdown-server
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Alex K (wtwf.com)
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2014-11-28 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: github-markdown-preview
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '3.1'
20
+ - - ">="
21
+ - !ruby/object:Gem::Version
22
+ version: 3.1.3
23
+ type: :runtime
24
+ prerelease: false
25
+ version_requirements: !ruby/object:Gem::Requirement
26
+ requirements:
27
+ - - "~>"
28
+ - !ruby/object:Gem::Version
29
+ version: '3.1'
30
+ - - ">="
31
+ - !ruby/object:Gem::Version
32
+ version: 3.1.3
33
+ - !ruby/object:Gem::Dependency
34
+ name: minitest
35
+ requirement: !ruby/object:Gem::Requirement
36
+ requirements:
37
+ - - "~>"
38
+ - !ruby/object:Gem::Version
39
+ version: '5.4'
40
+ type: :development
41
+ prerelease: false
42
+ version_requirements: !ruby/object:Gem::Requirement
43
+ requirements:
44
+ - - "~>"
45
+ - !ruby/object:Gem::Version
46
+ version: '5.4'
47
+ - !ruby/object:Gem::Dependency
48
+ name: bundler
49
+ requirement: !ruby/object:Gem::Requirement
50
+ requirements:
51
+ - - "~>"
52
+ - !ruby/object:Gem::Version
53
+ version: '1.7'
54
+ type: :development
55
+ prerelease: false
56
+ version_requirements: !ruby/object:Gem::Requirement
57
+ requirements:
58
+ - - "~>"
59
+ - !ruby/object:Gem::Version
60
+ version: '1.7'
61
+ - !ruby/object:Gem::Dependency
62
+ name: rake
63
+ requirement: !ruby/object:Gem::Requirement
64
+ requirements:
65
+ - - "~>"
66
+ - !ruby/object:Gem::Version
67
+ version: '10.3'
68
+ type: :development
69
+ prerelease: false
70
+ version_requirements: !ruby/object:Gem::Requirement
71
+ requirements:
72
+ - - "~>"
73
+ - !ruby/object:Gem::Version
74
+ version: '10.3'
75
+ description: Runs a webserver to preview Github markdown with live.js updating.
76
+ email: ruby@mail.wtwf.com
77
+ executables:
78
+ - github-markdown-server
79
+ extensions: []
80
+ extra_rdoc_files: []
81
+ files:
82
+ - ".gitignore"
83
+ - LICENSE
84
+ - README.md
85
+ - bin/github-markdown-server
86
+ - contrib/github-markdown-server.el
87
+ - contrib/p
88
+ - data/image/favicon.ico
89
+ - data/js/live.js
90
+ - github-markdown-server.gemspec
91
+ - lib/github-markdown-server.rb
92
+ - lib/github-markdown-server/resources.rb
93
+ - lib/github-markdown-server/server.rb
94
+ - lib/github-markdown-server/version.rb
95
+ homepage: https://github.com/arkarkark/github-markdown-server
96
+ licenses:
97
+ - MIT
98
+ metadata: {}
99
+ post_install_message:
100
+ rdoc_options: []
101
+ require_paths:
102
+ - lib
103
+ required_ruby_version: !ruby/object:Gem::Requirement
104
+ requirements:
105
+ - - ">="
106
+ - !ruby/object:Gem::Version
107
+ version: '0'
108
+ required_rubygems_version: !ruby/object:Gem::Requirement
109
+ requirements:
110
+ - - ">="
111
+ - !ruby/object:Gem::Version
112
+ version: '0'
113
+ requirements: []
114
+ rubyforge_project:
115
+ rubygems_version: 2.2.2
116
+ signing_key:
117
+ specification_version: 4
118
+ summary: Use your favorite editor to edit a markdown file, Run the server and open
119
+ the file. Saving in your editor updates instantly in the browser.
120
+ test_files: []