├── .gitignore ├── Gemfile ├── LICENSE.txt ├── README.md ├── Rakefile ├── bin └── cheatset ├── cheatset.gemspec └── lib ├── cheatset.rb └── cheatset ├── cli.rb ├── creator.rb ├── dsl ├── base.rb ├── category.rb ├── cheatsheet.rb ├── context.rb └── entry.rb ├── templates ├── .sass-cache │ └── c0630dfea9543a0a71b68aca4887e98819b89684 │ │ └── style.scssc ├── cheatset_resources │ ├── Open_Sans.woff │ ├── Open_Sans_Bold.woff │ ├── Open_Sans_Bold_Italic.woff │ ├── Open_Sans_Extrabold.woff │ ├── Open_Sans_Extrabold_Italic.woff │ ├── Open_Sans_Italic.woff │ ├── Open_Sans_Semibold.woff │ └── Open_Sans_Semibold_Italic.woff ├── style.css ├── style.scss └── template.haml └── version.rb /.gitignore: -------------------------------------------------------------------------------- 1 | *.gem 2 | *.rbc 3 | *.codekit 4 | .bundle 5 | .config 6 | .yardoc 7 | Gemfile.lock 8 | InstalledFiles 9 | _yardoc 10 | coverage 11 | doc/ 12 | lib/bundler/man 13 | pkg 14 | rdoc 15 | spec/reports 16 | test/tmp 17 | test/version_tmp 18 | tmp 19 | .sass-cache/ 20 | lib/cheatset/templates/template.html 21 | -------------------------------------------------------------------------------- /Gemfile: -------------------------------------------------------------------------------- 1 | source 'https://rubygems.org' 2 | gemspec 3 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | Copyright (c) 2013 Florian Dütsch 2 | 3 | MIT License 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining 6 | a copy of this software and associated documentation files (the 7 | "Software"), to deal in the Software without restriction, including 8 | without limitation the rights to use, copy, modify, merge, publish, 9 | distribute, sublicense, and/or sell copies of the Software, and to 10 | permit persons to whom the Software is furnished to do so, subject to 11 | the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be 14 | included in all copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 17 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 18 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 19 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 20 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 21 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 22 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # cheatset 2 | 3 | [![Gem Version](https://badge.fury.io/rb/cheatset.png)](http://badge.fury.io/rb/cheatset) 4 | 5 | Generate your own cheat sheets as docsets for [Dash](http://kapeli.com/dash)! 6 | Use this simple command line tool and write your cheat sheets in an easy 7 | language (Ruby DSL). 8 | 9 | ## Installation 10 | 11 | $ sudo gem install cheatset 12 | 13 | Note: this requires the Xcode Command Line Tools to be installed. Install them using this: 14 | 15 | $ xcode-select --install 16 | 17 | ## Contributions 18 | 19 | If you make a useful cheat sheet, please [contribute it](https://github.com/Kapeli/cheatsheets#readme) to Dash. 20 | 21 | ## Usage 22 | 23 | Write a file (here `sample.rb`) containing your cheat sheet data, e.g.: 24 | 25 | ```ruby 26 | cheatsheet do 27 | title 'Sample' # Will be displayed by Dash in the docset list 28 | docset_file_name 'Sample' # Used for the filename of the docset 29 | keyword 'sample' # Used as the initial search keyword (listed in Preferences > Docsets) 30 | # resources 'resources_dir' # An optional resources folder which can contain images or anything else 31 | 32 | introduction 'My *awesome* cheat sheet' # Optional, can contain Markdown or HTML 33 | 34 | # A cheat sheet must consist of categories 35 | category do 36 | id 'Windows' # Must be unique and is used as title of the category 37 | 38 | entry do 39 | command 'CMD+N' # Optional 40 | command 'CMD+SHIFT+N' # Multiple commands are supported 41 | name 'Create window' # A short name, can contain Markdown or HTML 42 | notes 'Some notes' # Optional longer explanation, can contain Markdown or HTML 43 | end 44 | entry do 45 | command 'CMD+W' 46 | name 'Close window' 47 | end 48 | end 49 | 50 | category do 51 | id 'Code' 52 | entry do 53 | name 'Code sample' 54 | notes <<-'END' 55 | ```ruby 56 | sample = "You can include code snippets as well" 57 | ``` 58 | Or anything else **Markdown** or HTML. 59 | END 60 | end 61 | end 62 | 63 | notes 'Some notes at the end of the cheat sheet' 64 | end 65 | ``` 66 | 67 | To convert this file to a docset, call 68 | 69 | $ cheatset generate sample.rb 70 | 71 | The following values may contain Markdown or HTML: 72 | 73 | * The `introduction` and the `notes` of the cheat sheet 74 | * The `name` and the `notes` of the entries 75 | 76 | Syntax highlighting is supported (see Ruby code in the sample). For a list of supported languages, see the [rouge](http://rouge.jneen.net/) [lexer repository](https://github.com/jneen/rouge/tree/master/spec/lexers) 77 | 78 | For more complete examples look at some of 79 | [the actual cheat sheets](https://github.com/Kapeli/cheatsheets/tree/master/cheatsheets). 80 | 81 | If you do not use Ruby or lack a working Ruby toolchain and still want to generate cheatsheets. 82 | 83 | You can use the `cheatset` Docker image. 84 | 85 | $ docker pull jonasbn/cheatset:latest 86 | $ docker run --rm -it --volume $PWD:/tmp --name cheatset jonasbn/cheatset:latest generate sample.rb 87 | 88 | For more details on the Docker image please visit the repositories on [DockerHub](https://hub.docker.com/repository/docker/jonasbn/cheatset) or [GitHub](https://github.com/jonasbn/docker-cheatset) 89 | 90 | ## Advanced Usage 91 | 92 | Apart from the attributes listed in the sample cheat sheet above, you can also use these: 93 | 94 | * `style` (under `cheatsheet`) - define any CSS style you want. See example [here](https://github.com/Kapeli/cheatsheets/blob/f9e40e30b6fde9063b7a0fb5de8fb203851b17df/cheatsheets/CSS_Named_Colors.rb#L7-L12) 95 | * `html_class` (under `category`) - define a HTML class to be added to a category. This can be used to define custom styling for each category 96 | * `td_command` (under `entry`) - just like `command`, but multiple ones are added in a separate column (as opposed to a separate row) 97 | * `td_notes` (under `entry`) - just like `notes` but can be repeated multiple times, each becoming a separate column 98 | * `html_notes` (under `entry`) - just like `notes`, but doesn't support Markdown 99 | * `index_name` (under `entry`) - this is not displayed in the cheat sheet at all. You can use it to define a separate index name (i.e what gets added to Dash's search index and is searchable in Dash). In other words, if this entry is not present, the value in `name` is used. 100 | 101 | ## Thanks 102 | 103 | [Nix-wie-weg](https://github.com/Nix-wie-weg/dasheets) for the initial code. 104 | -------------------------------------------------------------------------------- /Rakefile: -------------------------------------------------------------------------------- 1 | require "bundler/gem_tasks" 2 | -------------------------------------------------------------------------------- /bin/cheatset: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | 3 | $LOAD_PATH << File.expand_path('../../lib', __FILE__) 4 | require 'cheatset' 5 | require 'cheatset/cli' 6 | Cheatset::CLI.start 7 | -------------------------------------------------------------------------------- /cheatset.gemspec: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | lib = File.expand_path('../lib', __FILE__) 3 | $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib) 4 | require 'cheatset/version' 5 | 6 | Gem::Specification.new do |spec| 7 | spec.name = 'cheatset' 8 | spec.version = Cheatset::VERSION 9 | spec.authors = ['Bogdan Popescu'] 10 | spec.description = 'Generate cheat sheets for Dash' 11 | spec.summary = spec.description 12 | spec.homepage = 'https://github.com/Kapeli/cheatset' 13 | spec.license = 'MIT' 14 | 15 | spec.files = `git ls-files`.split($/) 16 | spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) } 17 | spec.test_files = spec.files.grep(%r{^(test|spec|features)/}) 18 | spec.require_paths = ['lib'] 19 | 20 | spec.add_development_dependency 'bundler', '~> 1.3' 21 | spec.add_development_dependency 'rake' 22 | 23 | spec.add_dependency 'thor', '>= 1.0.1', '< 2.0' 24 | spec.add_dependency 'haml', '> 5.2', '< 6.0' 25 | spec.add_dependency 'sqlite3', '>= 1.3.13', '< 1.4' 26 | spec.add_dependency 'plist', '>= 3.5.0', '< 4.0' 27 | spec.add_dependency 'redcarpet', '>= 3.5.1', '< 4.0' 28 | spec.add_dependency 'rouge', '>= 3.26.0', '< 4.0' 29 | spec.add_dependency 'sanitize', '>= 5.2.1', '< 6.0' 30 | spec.add_dependency 'unindent', '>= 1.0', '< 1.1' 31 | end 32 | -------------------------------------------------------------------------------- /lib/cheatset.rb: -------------------------------------------------------------------------------- 1 | require 'cheatset/version' 2 | 3 | %w(creator dsl/base dsl/cheatsheet dsl/category dsl/context 4 | dsl/entry).each do |file| 5 | require "cheatset/#{file}" 6 | end 7 | -------------------------------------------------------------------------------- /lib/cheatset/cli.rb: -------------------------------------------------------------------------------- 1 | require 'thor' 2 | 3 | module Rouge 4 | module Formatters 5 | class HTML < Formatter 6 | def stream_untableized(tokens, &b) # prevent Rouge from using
, we just want 
 7 |               yield "" if @wrap
 8 |               tokens.each{ |tok, val| span(tok, val, &b) }
 9 |               yield "
\n" if @wrap 10 | end 11 | end 12 | class HTMLPygments < Formatter 13 | def stream(tokens, &b) # prevent Rouge from using
, we just want 
14 |               yield %<
>
15 |               @inner.stream(tokens, &b)
16 |               yield "
" 17 | end 18 | end 19 | end 20 | end 21 | 22 | module Cheatset 23 | class CLI < Thor 24 | desc 'generate FILE', 'Generates cheatsheet out of a file' 25 | def generate(file) 26 | context = Cheatset::DSL::Context.new(file) 27 | context.generate 28 | end 29 | end 30 | end 31 | -------------------------------------------------------------------------------- /lib/cheatset/creator.rb: -------------------------------------------------------------------------------- 1 | require 'plist' 2 | require 'sqlite3' 3 | require 'fileutils' 4 | require 'haml' 5 | require 'ostruct' 6 | require 'cgi' 7 | require 'pathname' 8 | 9 | class Cheatset::Creator 10 | def initialize(cheatsheet, filename) 11 | @cheatsheet = cheatsheet 12 | @filename = filename 13 | @docset_path = "#{@cheatsheet.docset_file_name}.docset" 14 | @path = "#{@docset_path}/Contents/" 15 | end 16 | 17 | def generate 18 | FileUtils.rm_rf(@path) 19 | FileUtils.mkdir_p(@path) 20 | generate_html_file 21 | generate_plist_file 22 | generate_database 23 | end 24 | 25 | private 26 | 27 | def tpl_path 28 | File.expand_path('../templates', __FILE__) 29 | end 30 | 31 | def generate_html_file 32 | # HTML 33 | template = File.read("#{tpl_path}/template.haml") 34 | engine = Haml::Engine.new(template) 35 | out = engine.render(@cheatsheet) 36 | doc_path = "#{@path}Resources/Documents/" 37 | FileUtils.mkdir_p(doc_path) 38 | File.open("#{doc_path}index.html", 'w') { |file| file.write(out) } 39 | 40 | # (static) CSS 41 | FileUtils.cp("#{tpl_path}/style.css", doc_path) 42 | 43 | # resources 44 | FileUtils.cp_r("#{tpl_path}/cheatset_resources", doc_path) 45 | resources = @cheatsheet.resources 46 | if resources && !resources.empty? 47 | if Pathname.new(resources).absolute? 48 | resources_path = resources 49 | else 50 | base_dir = File.dirname(@filename) 51 | resources_path = "#{base_dir}/#{resources}" 52 | end 53 | 54 | FileUtils.cp_r(resources_path, doc_path) 55 | end 56 | end 57 | 58 | def generate_plist_file 59 | plist_data = { 60 | 'CFBundleIdentifier' => 'cheatsheet', 61 | 'CFBundleName' => (@cheatsheet.title) ? @cheatsheet.title : 'No Title', 62 | 'DocSetPlatformFamily' => 'cheatsheet', 63 | 'DashDocSetFamily' => 'cheatsheet', 64 | 'isDashDocset' => true, 65 | 'dashIndexFilePath' => 'index.html', 66 | 'DashDocSetPluginKeyword' => (@cheatsheet.platform) ? @cheatsheet.platform : (@cheatsheet.keyword) ? @cheatsheet.keyword : 'cheatsheet', 67 | 'DashDocSetKeyword' => (@cheatsheet.keyword) ? @cheatsheet.keyword : 'cheatsheet' 68 | } 69 | File.open("#{@path}Info.plist", 'w') do |file| 70 | file.write(Plist::Emit.dump(plist_data)) 71 | end 72 | end 73 | 74 | def generate_database 75 | sqlite_file = "#{@path}Resources/docSet.dsidx" 76 | db = SQLite3::Database.new(sqlite_file) 77 | db.busy_timeout = 100; 78 | db.execute <<-SQL 79 | CREATE TABLE searchIndex(id INTEGER PRIMARY KEY, name TEXT, 80 | type TEXT, path TEXT); 81 | CREATE UNIQUE INDEX anchor ON searchIndex (name, type, path); 82 | SQL 83 | 84 | sql = 'INSERT INTO searchIndex(name, type, path) VALUES (?, ?, ?)' 85 | db.execute(sql, @cheatsheet.title, 'Category', 86 | "index.html") 87 | 88 | @cheatsheet.categories.each do |category| 89 | category_strip = CGI.escape(category.id.strip).gsub(/\//, '%252F').gsub(/\+/, '%20'); 90 | if @cheatsheet.title != category.id 91 | db.execute(sql, category.id, 'Category', 92 | "index.html\#//dash_ref/Category/#{category_strip}/1") 93 | end 94 | category.entries.each_with_index do |entry, index| 95 | first_command = nil; 96 | if entry.command && entry.command.length > 0 97 | first_command = entry.command.first 98 | end 99 | href = (entry.name || entry.index_name) ? "index.html\#//dash_ref_#{category_strip}/Entry/#{CGI.escape((entry.index_name) ? entry.index_name.strip : entry.tags_stripped_name.strip).gsub(/\//, '%252F').gsub(/\+/, '%20')}/0" : (first_command) ? "index.html\#//dash_ref_#{category_strip}/Command/#{URI.escape(first_command).gsub(/\//, '%252F').gsub(/\+/, '%20')}/0" : "" 100 | if entry.command 101 | entry.command.each do |command| 102 | if(!command.strip.empty? && !entry.not_in_main_index) 103 | db.execute(sql, command.strip, 'Command', href) 104 | end 105 | end 106 | end 107 | if entry.td_command 108 | entry.td_command.each do |command| 109 | if(!command.strip.empty? && !entry.not_in_main_index) 110 | db.execute(sql, command.strip, 'Command', href) 111 | end 112 | end 113 | end 114 | if entry.name || entry.index_name 115 | if(!entry.not_in_main_index) 116 | db.execute(sql, (entry.index_name) ? entry.index_name.strip : entry.tags_stripped_name.strip, 'Entry', href) 117 | end 118 | end 119 | if entry.extra_index_name 120 | entry.extra_index_name.each do |extra_index_name| 121 | db.execute(sql, extra_index_name.strip, 'Entry', href) 122 | end 123 | end 124 | end 125 | end 126 | end 127 | end 128 | -------------------------------------------------------------------------------- /lib/cheatset/dsl/base.rb: -------------------------------------------------------------------------------- 1 | require 'redcarpet' 2 | require 'rouge' 3 | require 'rouge/plugins/redcarpet' 4 | require 'sanitize' 5 | require 'unindent' 6 | require 'cgi' 7 | 8 | class HTML < Redcarpet::Render::HTML 9 | include Rouge::Plugins::Redcarpet 10 | end 11 | 12 | module Cheatset 13 | module DSL 14 | class Base 15 | def initialize(&block) 16 | instance_eval(&block) 17 | end 18 | private 19 | 20 | def parse_markdown(str) 21 | markdown = Redcarpet::Markdown.new(HTML, :autolink => true, :hard_wrap =>true, :disable_indented_code_blocks => true, :fenced_code_blocks => true, :tables => true) 22 | markdown.render(str) 23 | end 24 | 25 | def self.define_attrs(*names) 26 | names.each do |name| 27 | define_method(name) do |val = nil| 28 | instance_variable_set("@#{name}", val) if val 29 | instance_variable_get("@#{name}") 30 | end 31 | end 32 | end 33 | def self.define_list_attrs(*names) 34 | names.each do |name| 35 | define_method(name) do |val = nil| 36 | if val 37 | array = instance_variable_get("@#{name}") 38 | if !array 39 | instance_variable_set("@#{name}", [val]) 40 | else 41 | instance_variable_set("@#{name}", array << val) 42 | end 43 | end 44 | instance_variable_get("@#{name}") 45 | end 46 | end 47 | end 48 | def self.define_markdown_list_attrs(*names) 49 | names.each do |name| 50 | define_method(name) do |val = nil| 51 | if val 52 | val = val.unindent 53 | val = parse_markdown(val) 54 | array = instance_variable_get("@#{name}") 55 | if !array 56 | instance_variable_set("@#{name}", [val]) 57 | else 58 | instance_variable_set("@#{name}", array << val) 59 | end 60 | end 61 | instance_variable_get("@#{name}") 62 | end 63 | end 64 | end 65 | def self.define_markdown_attrs(*names) 66 | names.each do |name| 67 | define_method(name) do |val = nil| 68 | if val 69 | val = val.unindent 70 | val = parse_markdown(val) 71 | instance_variable_set("@#{name}", val) 72 | end 73 | instance_variable_get("@#{name}") 74 | end 75 | define_method("tags_stripped_#{name}") do 76 | CGI.unescapeHTML(Sanitize.clean(send(name).gsub("\n", ' ').squeeze(' '))) 77 | end 78 | end 79 | end 80 | end 81 | end 82 | end 83 | -------------------------------------------------------------------------------- /lib/cheatset/dsl/category.rb: -------------------------------------------------------------------------------- 1 | module Cheatset 2 | module DSL 3 | class Category < Base 4 | attr_reader :entries 5 | define_attrs :id, :hasEntry, :html_class 6 | define_list_attrs :header 7 | 8 | def initialize(&block) 9 | @entries = [] 10 | super(&block) 11 | end 12 | def entry(&block) 13 | @entries << Cheatset::DSL::Entry.new(&block) 14 | end 15 | end 16 | end 17 | end 18 | -------------------------------------------------------------------------------- /lib/cheatset/dsl/cheatsheet.rb: -------------------------------------------------------------------------------- 1 | module Cheatset 2 | module DSL 3 | class Cheatsheet < Base 4 | attr_reader :categories 5 | define_attrs :title, :docset_file_name, :keyword, :source_url, :platform, :style, :head_inject, :resources 6 | define_markdown_attrs :introduction, :notes 7 | 8 | def initialize(&block) 9 | @categories = [] 10 | super(&block) 11 | end 12 | 13 | def category(&block) 14 | @categories << Cheatset::DSL::Category.new(&block) 15 | end 16 | end 17 | end 18 | end 19 | -------------------------------------------------------------------------------- /lib/cheatset/dsl/context.rb: -------------------------------------------------------------------------------- 1 | module Cheatset 2 | module DSL 3 | class Context 4 | def initialize(filename) 5 | instance_eval(File.read(filename), File.expand_path(filename)) 6 | @filename = filename 7 | end 8 | def generate 9 | Cheatset::Creator.new(@data, @filename).generate 10 | end 11 | private 12 | 13 | def cheatsheet(&block) 14 | @data = Cheatset::DSL::Cheatsheet.new(&block) 15 | end 16 | end 17 | end 18 | end 19 | -------------------------------------------------------------------------------- /lib/cheatset/dsl/entry.rb: -------------------------------------------------------------------------------- 1 | module Cheatset 2 | module DSL 3 | class Entry < Base 4 | define_list_attrs :command, :td_command, :extra_index_name 5 | define_attrs :index_name, :not_in_main_index, :html_notes 6 | define_markdown_attrs :name, :notes 7 | define_markdown_list_attrs :td_notes 8 | end 9 | end 10 | end 11 | -------------------------------------------------------------------------------- /lib/cheatset/templates/.sass-cache/c0630dfea9543a0a71b68aca4887e98819b89684/style.scssc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Kapeli/cheatset/fae39a314bd068cb3735d8d89f5a85bd5e5fc3c1/lib/cheatset/templates/.sass-cache/c0630dfea9543a0a71b68aca4887e98819b89684/style.scssc -------------------------------------------------------------------------------- /lib/cheatset/templates/cheatset_resources/Open_Sans.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Kapeli/cheatset/fae39a314bd068cb3735d8d89f5a85bd5e5fc3c1/lib/cheatset/templates/cheatset_resources/Open_Sans.woff -------------------------------------------------------------------------------- /lib/cheatset/templates/cheatset_resources/Open_Sans_Bold.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Kapeli/cheatset/fae39a314bd068cb3735d8d89f5a85bd5e5fc3c1/lib/cheatset/templates/cheatset_resources/Open_Sans_Bold.woff -------------------------------------------------------------------------------- /lib/cheatset/templates/cheatset_resources/Open_Sans_Bold_Italic.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Kapeli/cheatset/fae39a314bd068cb3735d8d89f5a85bd5e5fc3c1/lib/cheatset/templates/cheatset_resources/Open_Sans_Bold_Italic.woff -------------------------------------------------------------------------------- /lib/cheatset/templates/cheatset_resources/Open_Sans_Extrabold.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Kapeli/cheatset/fae39a314bd068cb3735d8d89f5a85bd5e5fc3c1/lib/cheatset/templates/cheatset_resources/Open_Sans_Extrabold.woff -------------------------------------------------------------------------------- /lib/cheatset/templates/cheatset_resources/Open_Sans_Extrabold_Italic.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Kapeli/cheatset/fae39a314bd068cb3735d8d89f5a85bd5e5fc3c1/lib/cheatset/templates/cheatset_resources/Open_Sans_Extrabold_Italic.woff -------------------------------------------------------------------------------- /lib/cheatset/templates/cheatset_resources/Open_Sans_Italic.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Kapeli/cheatset/fae39a314bd068cb3735d8d89f5a85bd5e5fc3c1/lib/cheatset/templates/cheatset_resources/Open_Sans_Italic.woff -------------------------------------------------------------------------------- /lib/cheatset/templates/cheatset_resources/Open_Sans_Semibold.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Kapeli/cheatset/fae39a314bd068cb3735d8d89f5a85bd5e5fc3c1/lib/cheatset/templates/cheatset_resources/Open_Sans_Semibold.woff -------------------------------------------------------------------------------- /lib/cheatset/templates/cheatset_resources/Open_Sans_Semibold_Italic.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Kapeli/cheatset/fae39a314bd068cb3735d8d89f5a85bd5e5fc3c1/lib/cheatset/templates/cheatset_resources/Open_Sans_Semibold_Italic.woff -------------------------------------------------------------------------------- /lib/cheatset/templates/style.css: -------------------------------------------------------------------------------- 1 | h1, h2, h3, p, blockquote { 2 | margin: 0; 3 | padding: 0; } 4 | 5 | @font-face { 6 | font-family: 'Open Sans'; 7 | font-style: normal; 8 | font-weight: 400; 9 | src: local("Open Sans"), local("OpenSans"), url(cheatset_resources/Open_Sans.woff) format("woff"); } 10 | @font-face { 11 | font-family: 'Open Sans'; 12 | font-style: normal; 13 | font-weight: 600; 14 | src: local("Open Sans Semibold"), local("OpenSans-Semibold"), url(cheatset_resources/Open_Sans_Semibold.woff) format("woff"); } 15 | @font-face { 16 | font-family: 'Open Sans'; 17 | font-style: normal; 18 | font-weight: 700; 19 | src: local("Open Sans Bold"), local("OpenSans-Bold"), url(cheatset_resources/Open_Sans_Bold.woff) format("woff"); } 20 | @font-face { 21 | font-family: 'Open Sans'; 22 | font-style: normal; 23 | font-weight: 800; 24 | src: local("Open Sans Extrabold"), local("OpenSans-Extrabold"), url(cheatset_resources/Open_Sans_Extrabold.woff) format("woff"); } 25 | @font-face { 26 | font-family: 'Open Sans'; 27 | font-style: italic; 28 | font-weight: 400; 29 | src: local("Open Sans Italic"), local("OpenSans-Italic"), url(cheatset_resources/Open_Sans_Italic.woff) format("woff"); } 30 | @font-face { 31 | font-family: 'Open Sans'; 32 | font-style: italic; 33 | font-weight: 600; 34 | src: local("Open Sans Semibold Italic"), local("OpenSans-SemiboldItalic"), url(cheatset_resources/Open_Sans_Semibold_Italic.woff) format("woff"); } 35 | @font-face { 36 | font-family: 'Open Sans'; 37 | font-style: italic; 38 | font-weight: 700; 39 | src: local("Open Sans Bold Italic"), local("OpenSans-BoldItalic"), url(cheatset_resources/Open_Sans_Bold_Italic.woff) format("woff"); } 40 | @font-face { 41 | font-family: 'Open Sans'; 42 | font-style: italic; 43 | font-weight: 800; 44 | src: local("Open Sans Extrabold Italic"), local("OpenSans-ExtraboldItalic"), url(cheatset_resources/Open_Sans_Extrabold_Italic.woff) format("woff"); } 45 | body { 46 | font-family: 'Open Sans', sans-serif; 47 | font-size: 16px; 48 | color: #000; 49 | background-color: #fff; 50 | margin: 0; } 51 | 52 | code, pre { 53 | font-family: Menlo, Consolas, "Liberation Mono", Courier, monospace; 54 | font-size: 15px; } 55 | 56 | code { 57 | margin: 0; 58 | border: 1px solid #ddd; 59 | background-color: #f8f8f8; 60 | border-radius: 3px; 61 | white-space: nowrap; } 62 | 63 | .name code { 64 | vertical-align: 1px; } 65 | 66 | code:before, code:after { 67 | content: "\00a0"; } 68 | 69 | header { 70 | color: #efefef; 71 | background-color: #666; 72 | padding: 0px 10px 3px 10px; } 73 | 74 | h1 { 75 | font-size: 35px; 76 | font-weight: 600; } 77 | 78 | footer { 79 | background-color: #666; 80 | color: #efefef; 81 | text-align: center; 82 | padding: 3px 0px; } 83 | footer a { 84 | color: #efefef; } 85 | 86 | section.notes { 87 | margin-top: 1em; } 88 | section.notes h2 { 89 | color: #666; 90 | font-size: 1.5em; } 91 | 92 | article { 93 | margin: 2em 1em; } 94 | 95 | @media print { 96 | section.category { 97 | page-break-inside: avoid; 98 | break-inside: avoid; 99 | } 100 | } 101 | 102 | section.category { 103 | border: 2px solid #666; 104 | border-radius: 6px 6px; 105 | background-color: #666; 106 | margin: 2em 0; 107 | overflow: hidden; 108 | padding-bottom: 5px; } 109 | section.category h2 { 110 | color: #fff; 111 | font-size: 1.5em; 112 | text-align: center; 113 | margin-top: -2px; 114 | font-weight: 600; } 115 | 116 | table { 117 | background-color: #fff; 118 | border-collapse: collapse; 119 | width: 100%; } 120 | 121 | td { 122 | padding: 13px 8px 0px 8px; 123 | border-left: 1px solid #d7d7d7; } 124 | 125 | th { 126 | border-left: 1px solid #d7d7d7; } 127 | 128 | tr { 129 | border-bottom: 1px dotted #d7d7d7; } 130 | 131 | tr:last-child { 132 | border-bottom: none; } 133 | 134 | td.command, td.td_command { 135 | width: 1%; 136 | white-space: nowrap; 137 | vertical-align:top; 138 | padding: 9px 8px 4px 7px; 139 | text-align: right; } 140 | td.command code, td.td_command code { 141 | padding: .1em 0.2em; 142 | box-shadow: 0 1px 0px rgba(0, 0, 0, 0.2), 0 0 0 2px #fff inset; 143 | border-radius: 3px; 144 | border: 1px solid #ccc; 145 | background-color: #efefef; 146 | color: #333; } 147 | 148 | td.td_command { 149 | text-align: center; } 150 | 151 | td.description .name { 152 | font-size: 1.2em; } 153 | 154 | th { 155 | background: #efefef; 156 | padding: 5px 12px 5px 8px; 157 | text-align: left; 158 | border-bottom: 1px solid #d7d7d7; 159 | font-weight: 600; } 160 | 161 | th:nth-child(1), td:nth-child(1) { 162 | border-left: none; } 163 | 164 | a { 165 | color: #666; } 166 | 167 | p { 168 | margin: 0 0 7px; } 169 | 170 | .highlight { 171 | background-color: #f8f8f8; 172 | border: 1px solid #ccc; 173 | padding: 6px 10px; 174 | border-radius: 3px; 175 | margin-right: 1px; 176 | white-space: pre-wrap; 177 | word-wrap: break-word; } 178 | 179 | .c { 180 | color: #999988; 181 | font-style: italic; } 182 | 183 | .k { 184 | font-weight: bold; } 185 | 186 | .o { 187 | font-weight: bold; } 188 | 189 | .cm { 190 | color: #999988; 191 | font-style: italic; } 192 | 193 | .cp { 194 | color: #999999; 195 | font-weight: bold; } 196 | 197 | .c1 { 198 | color: #999988; 199 | font-style: italic; } 200 | 201 | .cs { 202 | color: #999999; 203 | font-weight: bold; 204 | font-style: italic; } 205 | 206 | .gd { 207 | color: #000000; 208 | background-color: #ffdddd; } 209 | 210 | .gd .x { 211 | color: #000000; 212 | background-color: #ffaaaa; } 213 | 214 | .ge { 215 | font-style: italic; } 216 | 217 | .gr { 218 | color: #aa0000; } 219 | 220 | .gh { 221 | color: #999999; } 222 | 223 | .gi { 224 | color: #000000; 225 | background-color: #ddffdd; } 226 | 227 | .gi .x { 228 | color: #000000; 229 | background-color: #aaffaa; } 230 | 231 | .go { 232 | color: #888888; } 233 | 234 | .gp { 235 | color: #555555; } 236 | 237 | .gs { 238 | font-weight: bold; } 239 | 240 | .gu { 241 | color: #800080; 242 | font-weight: bold; } 243 | 244 | .gt { 245 | color: #aa0000; } 246 | 247 | .kc { 248 | font-weight: bold; } 249 | 250 | .kd { 251 | font-weight: bold; } 252 | 253 | .kn { 254 | font-weight: bold; } 255 | 256 | .kp { 257 | font-weight: bold; } 258 | 259 | .kr { 260 | font-weight: bold; } 261 | 262 | .kt { 263 | color: #445588; 264 | font-weight: bold; } 265 | 266 | .m { 267 | color: #009999; } 268 | 269 | .s { 270 | color: #dd1144; } 271 | 272 | .n { 273 | color: #333333; } 274 | 275 | .na { 276 | color: teal; } 277 | 278 | .nb { 279 | color: #0086b3; } 280 | 281 | .nc { 282 | color: #445588; 283 | font-weight: bold; } 284 | 285 | .no { 286 | color: teal; } 287 | 288 | .ni { 289 | color: purple; } 290 | 291 | .ne { 292 | color: #990000; 293 | font-weight: bold; } 294 | 295 | .nf { 296 | color: #990000; 297 | font-weight: bold; } 298 | 299 | .nn { 300 | color: #555555; } 301 | 302 | .nt { 303 | color: navy; } 304 | 305 | .nv { 306 | color: teal; } 307 | 308 | .ow { 309 | font-weight: bold; } 310 | 311 | .w { 312 | color: #bbbbbb; } 313 | 314 | .mf { 315 | color: #009999; } 316 | 317 | .mh { 318 | color: #009999; } 319 | 320 | .mi { 321 | color: #009999; } 322 | 323 | .mo { 324 | color: #009999; } 325 | 326 | .sb { 327 | color: #dd1144; } 328 | 329 | .sc { 330 | color: #dd1144; } 331 | 332 | .sd { 333 | color: #dd1144; } 334 | 335 | .s2 { 336 | color: #dd1144; } 337 | 338 | .se { 339 | color: #dd1144; } 340 | 341 | .sh { 342 | color: #dd1144; } 343 | 344 | .si { 345 | color: #dd1144; } 346 | 347 | .sx { 348 | color: #dd1144; } 349 | 350 | .sr { 351 | color: #009926; } 352 | 353 | .s1 { 354 | color: #dd1144; } 355 | 356 | .ss { 357 | color: #990073; } 358 | 359 | .bp { 360 | color: #999999; } 361 | 362 | .vc { 363 | color: teal; } 364 | 365 | .vg { 366 | color: teal; } 367 | 368 | .vi { 369 | color: teal; } 370 | 371 | .il { 372 | color: #009999; } 373 | 374 | .gc { 375 | color: #999; 376 | background-color: #EAF2F5; } 377 | 378 | pre { 379 | padding: 15px; 380 | line-height: 17px; 381 | margin-top: 0px; 382 | margin-bottom: 9px; } 383 | 384 | .name { 385 | margin-top: -4px; } 386 | 387 | ul { 388 | padding-left: 24px; } 389 | 390 | .scrollable { 391 | overflow-x: auto; } 392 | 393 | a { 394 | -ms-word-break: break-all; 395 | -ms-word-wrap: break-all; 396 | -webkit-word-break: break-word; 397 | -webkit-word-wrap: break-word; 398 | word-break: break-word; 399 | word-wrap: break-word; } 400 | -------------------------------------------------------------------------------- /lib/cheatset/templates/style.scss: -------------------------------------------------------------------------------- 1 | $white: #fff; 2 | $light_gray: #efefef; 3 | $dark_gray: #666; 4 | $lighter_gray: #d7d7d7; 5 | $black: #000; 6 | //////////////////////////////////////////////////////////////////////////////// 7 | h1, h2, h3, p, blockquote { 8 | margin: 0; 9 | padding: 0; 10 | } 11 | @font-face { 12 | font-family: 'Open Sans'; 13 | font-style: normal; 14 | font-weight: 400; 15 | src: local('Open Sans'), local('OpenSans'), url(cheatset_resources/Open_Sans.woff) format('woff'); 16 | } 17 | @font-face { 18 | font-family: 'Open Sans'; 19 | font-style: normal; 20 | font-weight: 600; 21 | src: local('Open Sans Semibold'), local('OpenSans-Semibold'), url(cheatset_resources/Open_Sans_Semibold.woff) format('woff'); 22 | } 23 | @font-face { 24 | font-family: 'Open Sans'; 25 | font-style: normal; 26 | font-weight: 700; 27 | src: local('Open Sans Bold'), local('OpenSans-Bold'), url(cheatset_resources/Open_Sans_Bold.woff) format('woff'); 28 | } 29 | @font-face { 30 | font-family: 'Open Sans'; 31 | font-style: normal; 32 | font-weight: 800; 33 | src: local('Open Sans Extrabold'), local('OpenSans-Extrabold'), url(cheatset_resources/Open_Sans_Extrabold.woff) format('woff'); 34 | } 35 | @font-face { 36 | font-family: 'Open Sans'; 37 | font-style: italic; 38 | font-weight: 400; 39 | src: local('Open Sans Italic'), local('OpenSans-Italic'), url(cheatset_resources/Open_Sans_Italic.woff) format('woff'); 40 | } 41 | @font-face { 42 | font-family: 'Open Sans'; 43 | font-style: italic; 44 | font-weight: 600; 45 | src: local('Open Sans Semibold Italic'), local('OpenSans-SemiboldItalic'), url(cheatset_resources/Open_Sans_Semibold_Italic.woff) format('woff'); 46 | } 47 | @font-face { 48 | font-family: 'Open Sans'; 49 | font-style: italic; 50 | font-weight: 700; 51 | src: local('Open Sans Bold Italic'), local('OpenSans-BoldItalic'), url(cheatset_resources/Open_Sans_Bold_Italic.woff) format('woff'); 52 | } 53 | @font-face { 54 | font-family: 'Open Sans'; 55 | font-style: italic; 56 | font-weight: 800; 57 | src: local('Open Sans Extrabold Italic'), local('OpenSans-ExtraboldItalic'), url(cheatset_resources/Open_Sans_Extrabold_Italic.woff) format('woff'); 58 | } 59 | 60 | body { 61 | font-family: 'Open Sans', sans-serif; 62 | font-size: 14px; 63 | color: $black; 64 | background-color: $white; 65 | margin: 0; 66 | } 67 | code, pre { 68 | font-family: Menlo, Consolas, "Liberation Mono", Courier, monospace; 69 | font-size:13px; 70 | } 71 | 72 | code { 73 | margin:0; 74 | border:1px solid #ddd; 75 | background-color:#f8f8f8; 76 | border-radius:3px; 77 | white-space:nowrap; 78 | } 79 | 80 | .name code { 81 | vertical-align:1px; 82 | } 83 | 84 | code:before, code:after { 85 | content: "\00a0"; 86 | } 87 | 88 | //////////////////////////////////////////////////////////////////////////////// 89 | header { 90 | color: $light_gray; 91 | background-color: $dark_gray; 92 | padding: 0px 10px 3px 10px; 93 | } 94 | h1 { 95 | font-size: 35px; 96 | font-weight:600; 97 | } 98 | 99 | //////////////////////////////////////////////////////////////////////////////// 100 | footer { 101 | background-color: $dark_gray; 102 | color: $light_gray; 103 | text-align: center; 104 | padding:3px 0px; 105 | a { 106 | color: $light_gray; 107 | } 108 | } 109 | //////////////////////////////////////////////////////////////////////////////// 110 | // notes 111 | section.notes { 112 | margin-top: 1em; 113 | h2 { 114 | color: $dark_gray; 115 | font-size: 1.5em; 116 | } 117 | } 118 | //////////////////////////////////////////////////////////////////////////////// 119 | article { 120 | margin: 2em 1em; 121 | } 122 | 123 | @media print { 124 | section.category { 125 | page-break-inside: avoid; 126 | break-inside: avoid; 127 | } 128 | } 129 | 130 | section.category { 131 | border: 2px solid $dark_gray; 132 | border-radius: 6px 6px; 133 | background-color: $dark_gray; 134 | margin: 2em 0; 135 | overflow: hidden; 136 | h2 { 137 | color: $white; 138 | font-size: 1.5em; 139 | text-align: center; 140 | margin-top: -2px; 141 | font-weight:600; 142 | } 143 | padding-bottom: 5px; 144 | } 145 | table { 146 | background-color: $white; 147 | border-collapse: collapse; 148 | width: 100%; 149 | } 150 | td { 151 | padding: 13px 8px 0px 8px; 152 | border-left:1px solid $lighter_gray; 153 | } 154 | th { 155 | border-left:1px solid $lighter_gray; 156 | } 157 | tr { 158 | border-bottom:1px dotted $lighter_gray; 159 | } 160 | tr:last-child { 161 | border-bottom:none; 162 | } 163 | td.command { 164 | width: 1%; 165 | white-space: nowrap; 166 | vertical-align:top; 167 | padding: 9px 8px 4px 7px; 168 | text-align:right; 169 | // border-right:1px solid $lighter_gray; 170 | code { 171 | // Nice key styling: 172 | // https://developers.google.com/chrome-developer-tools/docs/shortcuts 173 | padding: .1em 0.2em; 174 | box-shadow: 0 1px 0px rgba(0, 0, 0, 0.2), 0 0 0 2px #fff inset; 175 | border-radius: 3px; 176 | border: 1px solid #ccc; 177 | background-color: $light_gray; 178 | color: #333; 179 | } 180 | } 181 | 182 | td.td_command { 183 | @extend td.command; 184 | text-align:center; 185 | } 186 | 187 | td.description { 188 | .name { 189 | font-size: 1.2em; 190 | } 191 | } 192 | 193 | th { 194 | background: $light_gray; 195 | padding:5px 12px 5px 8px; 196 | text-align: left; 197 | border-bottom: 1px solid $lighter_gray; 198 | font-weight:600; 199 | } 200 | 201 | th:nth-child(1), td:nth-child(1) { 202 | border-left:none; 203 | } 204 | 205 | a { 206 | color: $dark_gray; 207 | } 208 | 209 | p { 210 | margin:0 0 7px; 211 | } 212 | 213 | .highlight { background-color: #f8f8f8; border: 1px solid #ccc; padding: 6px 10px; border-radius: 3px; margin-right:1px; white-space: pre-wrap; word-wrap:break-word;} 214 | .c { color: #999988; font-style: italic; } 215 | .k { font-weight: bold; } 216 | .o { font-weight: bold; } 217 | .cm { color: #999988; font-style: italic; } 218 | .cp { color: #999999; font-weight: bold; } 219 | .c1 { color: #999988; font-style: italic; } 220 | .cs { color: #999999; font-weight: bold; font-style: italic; } 221 | .gd { color: #000000; background-color: #ffdddd; } 222 | .gd .x { color: #000000; background-color: #ffaaaa; } 223 | .ge { font-style: italic; } 224 | .gr { color: #aa0000; } 225 | .gh { color: #999999; } 226 | .gi { color: #000000; background-color: #ddffdd; } 227 | .gi .x { color: #000000; background-color: #aaffaa; } 228 | .go { color: #888888; } 229 | .gp { color: #555555; } 230 | .gs { font-weight: bold; } 231 | .gu { color: #800080; font-weight: bold; } 232 | .gt { color: #aa0000; } 233 | .kc { font-weight: bold; } 234 | .kd { font-weight: bold; } 235 | .kn { font-weight: bold; } 236 | .kp { font-weight: bold; } 237 | .kr { font-weight: bold; } 238 | .kt { color: #445588; font-weight: bold; } 239 | .m { color: #009999; } 240 | .s { color: #dd1144; } 241 | .n { color: #333333; } 242 | .na { color: teal; } 243 | .nb { color: #0086b3; } 244 | .nc { color: #445588; font-weight: bold; } 245 | .no { color: teal; } 246 | .ni { color: purple; } 247 | .ne { color: #990000; font-weight: bold; } 248 | .nf { color: #990000; font-weight: bold; } 249 | .nn { color: #555555; } 250 | .nt { color: navy; } 251 | .nv { color: teal; } 252 | .ow { font-weight: bold; } 253 | .w { color: #bbbbbb; } 254 | .mf { color: #009999; } 255 | .mh { color: #009999; } 256 | .mi { color: #009999; } 257 | .mo { color: #009999; } 258 | .sb { color: #dd1144; } 259 | .sc { color: #dd1144; } 260 | .sd { color: #dd1144; } 261 | .s2 { color: #dd1144; } 262 | .se { color: #dd1144; } 263 | .sh { color: #dd1144; } 264 | .si { color: #dd1144; } 265 | .sx { color: #dd1144; } 266 | .sr { color: #009926; } 267 | .s1 { color: #dd1144; } 268 | .ss { color: #990073; } 269 | .bp { color: #999999; } 270 | .vc { color: teal; } 271 | .vg { color: teal; } 272 | .vi { color: teal; } 273 | .il { color: #009999; } 274 | .gc { color: #999; background-color: #EAF2F5; } 275 | 276 | pre { 277 | padding: 15px; 278 | line-height: 17px; 279 | margin-top: 0px; 280 | margin-bottom: 9px; 281 | } 282 | 283 | .name { 284 | margin-top: -4px; 285 | } 286 | 287 | ul { 288 | padding-left: 24px; 289 | } 290 | 291 | .scrollable { 292 | overflow-x:auto; 293 | } 294 | 295 | a { 296 | -ms-word-break: break-all; 297 | -ms-word-wrap: break-all; 298 | -webkit-word-break: break-word; 299 | -webkit-word-wrap: break-word; 300 | word-break: break-word; 301 | word-wrap: break-word; 302 | } -------------------------------------------------------------------------------- /lib/cheatset/templates/template.haml: -------------------------------------------------------------------------------- 1 | !!! 2 | %html 3 | %head 4 | %meta{charset: 'utf-8'} 5 | %title= title 6 | %link{rel: 'stylesheet', href: 'style.css'} 7 | - if style 8 | %style{type: 'text/css'}= style 9 | - if head_inject 10 | = head_inject 11 | - categories.each do |category| 12 | %link{href: "//dash_ref/Category/#{category.id.strip.gsub(/\//, '%2F')}/1"} 13 | - category.hasEntry(false) 14 | - category.entries.each_with_index do |entry, index| 15 | - if entry.name || entry.index_name 16 | - category.hasEntry(true) 17 | %link{href: "//dash_ref_#{category.id.strip.gsub(/\//, '%2F')}/Entry/#{(entry.name) ? entry.tags_stripped_name.strip.gsub(/\//, '%2F') : entry.index_name.strip.gsub(/\//, '%2F')}/0"} 18 | - elsif entry.command && entry.command.length > 0 19 | - category.hasEntry(true) 20 | %link{href: "//dash_ref_#{category.id.strip.gsub(/\//, '%2F')}/Command/#{entry.command.first.strip.gsub(/\//, '%2F')}/0"} 21 | - if !category.hasEntry 22 | %link{href: "//dash_ref/Entry/#{category.id.strip.gsub(/\//, '%2F')}/0"} 23 | 24 | %body 25 | %header 26 | %h1= title 27 | 28 | %article 29 | %p~ introduction 30 | 31 | - categories.each do |category| 32 | %section.category{class: category.html_class} 33 | - if !category.hasEntry 34 | %a{name: "//dash_ref/Entry/#{category.id.strip.gsub(/\//, '%2F')}/0"} 35 | %h2{id:"//dash_ref/Category/#{category.id.strip.gsub(/\//, '%2F')}/1"} 36 | = category.id 37 | %div.scrollable 38 | %table 39 | - if category.header 40 | %tr 41 | - category.header.each do |header| 42 | %th~ header 43 | 44 | - category.entries.each_with_index do |entry, index| 45 | %tr{id: ((entry.name || entry.index_name) ? "//dash_ref_#{category.id.strip.gsub(/\//, '%2F')}/Entry/#{(entry.name) ? entry.tags_stripped_name.strip.gsub(/\//, '%2F') : entry.index_name.strip.gsub(/\//, '%2F')}/0" : "//dash_ref_#{category.id.strip.gsub(/\//, '%2F')}/Command/#{entry.command.first.strip.gsub(/\//, '%2F')}/0" if (entry.name || entry.index_name || (entry.command && entry.command.length > 0)) )} 46 | - if entry.command 47 | %td.command 48 | - entry.command.each do |command| 49 | %p 50 | %code= CGI.escapeHTML(command) 51 | - if entry.td_command 52 | - entry.td_command.each do |command| 53 | %td.td_command 54 | - if !command.empty? 55 | %code= CGI.escapeHTML(command) 56 | - if entry.name || entry.notes || entry.html_notes 57 | %td.description{:colspan => ("2" unless entry.command || entry.td_command || entry.td_notes)} 58 | .name~ entry.name 59 | .notes~ entry.notes 60 | .notes~ entry.html_notes 61 | - if entry.td_notes 62 | - entry.td_notes.each do |notes| 63 | %td.td_notes 64 | - if !notes.empty? 65 | .td_notes~ notes 66 | - if notes 67 | %section.notes 68 | %h2 Notes 69 | ~ notes 70 | %footer 71 | - if source_url 72 | You can modify and improve this cheat sheet here 73 | - else 74 | Generated with cheatset -------------------------------------------------------------------------------- /lib/cheatset/version.rb: -------------------------------------------------------------------------------- 1 | module Cheatset 2 | VERSION = '1.4.8' 3 | end 4 | --------------------------------------------------------------------------------