├── .gitignore ├── .gitmodules ├── .travis.yml ├── LICENSE ├── README.md ├── USER_GUIDE.md ├── data ├── icons │ ├── 16 │ │ └── writeas-gtk.png │ ├── 24 │ │ └── writeas-gtk.png │ ├── 32 │ │ └── writeas-gtk.png │ ├── 48 │ │ └── writeas-gtk.png │ ├── 64 │ │ └── writeas-gtk.png │ └── 128 │ │ └── writeas-gtk.png ├── meson.build ├── writeas-gtk.appdata.xml.in └── writeas-gtk.desktop.in ├── debian ├── changelog ├── compat ├── control ├── copyright ├── rules └── source │ └── format ├── meson.build ├── meson ├── build-cli.sh └── post_install.py ├── meson_options.txt ├── screenshot-monospace.png ├── screenshot-sans-light.png ├── screenshot-serif-dark.png ├── screenshot-serif-light.png └── src ├── Granite ├── Accels.vala └── ModeSwitch.vala ├── application.vala ├── github.com ├── BurntSushi │ └── toml │ │ ├── COMPATIBLE │ │ ├── COPYING │ │ ├── Makefile │ │ ├── README.md │ │ ├── _examples │ │ ├── example.go │ │ ├── example.toml │ │ ├── hard.toml │ │ ├── implicit.toml │ │ ├── invalid-apples.toml │ │ ├── invalid.toml │ │ ├── readme1.toml │ │ └── readme2.toml │ │ ├── cmd │ │ ├── toml-test-decoder │ │ │ ├── COPYING │ │ │ ├── README.md │ │ │ └── main.go │ │ ├── toml-test-encoder │ │ │ ├── COPYING │ │ │ ├── README.md │ │ │ └── main.go │ │ └── tomlv │ │ │ ├── COPYING │ │ │ ├── README.md │ │ │ └── main.go │ │ ├── decode.go │ │ ├── decode_meta.go │ │ ├── decode_test.go │ │ ├── doc.go │ │ ├── encode.go │ │ ├── encode_test.go │ │ ├── encoding_types.go │ │ ├── encoding_types_1.1.go │ │ ├── lex.go │ │ ├── parse.go │ │ ├── session.vim │ │ ├── type_check.go │ │ └── type_fields.go ├── atotto │ └── clipboard │ │ ├── LICENSE │ │ ├── README.md │ │ ├── clipboard.go │ │ ├── clipboard_darwin.go │ │ ├── clipboard_test.go │ │ ├── clipboard_unix.go │ │ ├── clipboard_windows.go │ │ ├── cmd │ │ ├── gocopy │ │ │ └── gocopy.go │ │ └── gopaste │ │ │ └── gopaste.go │ │ └── example_test.go └── mitchellh │ └── go-homedir │ ├── LICENSE │ ├── README.md │ ├── homedir.go │ └── homedir_test.go ├── gopkg.in ├── urfave │ └── cli.v1 │ │ ├── CHANGELOG.md │ │ ├── LICENSE │ │ ├── README.md │ │ ├── altsrc │ │ ├── altsrc.go │ │ ├── flag.go │ │ ├── flag_generated.go │ │ ├── flag_test.go │ │ ├── helpers_test.go │ │ ├── input_source_context.go │ │ ├── map_input_source.go │ │ ├── toml_command_test.go │ │ ├── toml_file_loader.go │ │ ├── yaml_command_test.go │ │ └── yaml_file_loader.go │ │ ├── app.go │ │ ├── app_test.go │ │ ├── appveyor.yml │ │ ├── autocomplete │ │ ├── bash_autocomplete │ │ └── zsh_autocomplete │ │ ├── category.go │ │ ├── cli.go │ │ ├── command.go │ │ ├── command_test.go │ │ ├── context.go │ │ ├── context_test.go │ │ ├── errors.go │ │ ├── errors_test.go │ │ ├── flag-types.json │ │ ├── flag.go │ │ ├── flag_generated.go │ │ ├── flag_test.go │ │ ├── funcs.go │ │ ├── generate-flag-types │ │ ├── help.go │ │ ├── help_test.go │ │ ├── helpers_test.go │ │ ├── helpers_unix_test.go │ │ ├── helpers_windows_test.go │ │ └── runtests └── yaml.v2 │ ├── LICENSE │ ├── LICENSE.libyaml │ ├── README.md │ ├── apic.go │ ├── decode.go │ ├── decode_test.go │ ├── emitterc.go │ ├── encode.go │ ├── encode_test.go │ ├── parserc.go │ ├── readerc.go │ ├── resolve.go │ ├── scannerc.go │ ├── sorter.go │ ├── suite_test.go │ ├── writerc.go │ ├── yaml.go │ ├── yamlh.go │ └── yamlprivateh.go ├── meson.build └── window.vala /.gitignore: -------------------------------------------------------------------------------- 1 | *.swp 2 | *~ 3 | 4 | build 5 | .ninja_* 6 | build.ninja 7 | data/writeas 8 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "src/github.com/writeas/writeas-cli"] 2 | path = src/github.com/writeas/writeas-cli 3 | url = https://github.com/writeas/writeas-cli.git 4 | [submodule "fonts/lora"] 5 | path = fonts/lora 6 | url = https://code.as/writeas/fonts-lora.git 7 | branch = include 8 | [submodule "src/code.as/core/socks"] 9 | path = src/code.as/core/socks 10 | url = https://code.as/core/socks.git 11 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | language: node_js 4 | 5 | node_js: 6 | - lts/* 7 | 8 | sudo: required 9 | 10 | services: 11 | - docker 12 | 13 | addons: 14 | apt: 15 | sources: 16 | - ubuntu-toolchain-r-test 17 | packages: 18 | - libstdc++-5-dev 19 | 20 | install: 21 | - npm i -g @elementaryos/houston 22 | 23 | script: 24 | - houston ci 25 | 26 | notifications: 27 | email: false 28 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Write.as GTK App 2 | 3 | [![Get the app from Write.as](https://write.as/img/downloadwriteas.png)](https://write.as/apps/desktop)   4 | [![Get the app on AppCenter](https://write.as/img/appcenter.png)](https://appcenter.elementary.io/com.github.writeas.writeas-gtk) 5 | 6 | A Write.as desktop app that targets all freedesktop.org compliant desktops, e.g. 7 | GNU/Linux, FreeBSD, etc; basically everything except Windows, Mac, iOS, and 8 | Android. It lets you compose and publish posts to [Write.as](https://write.as/). 9 | 10 | For a UI toolkit it uses GTK, and relies on the [writeas-cli](https://github.com/writeas/writeas-cli) for API calls and post management. 11 | 12 | --- 13 | 14 | **This is a fork of the [writeas-gtk application](https://code.as/writeas/writeas-gtk), containing necessary changes to release the app for elementaryOS.** 15 | 16 | This repo shouldn't be used by other package maintainers. Version 1.0.x numbers are out of sync with the [official releases](https://code.as/writeas/writeas-gtk/releases). 17 | 18 | ## Usage 19 | 20 | See the [User Guide](https://code.as/writeas/writeas-gtk/src/branch/master/USER_GUIDE.md). 21 | 22 | ## Installation 23 | Write.as GTK uses the [Meson/Ninja](http://mesonbuild.com/) build system, and as such you can install it on 24 | any FreeDesktop.Org compatible system using: 25 | 26 | ```bash 27 | # Install latest version of meson 28 | # Either via pip: 29 | pip3 install meson 30 | # Or, if you need to build the .deb: 31 | sudo add-apt-repository ppa:jonathonf/meson 32 | sudo apt update 33 | sudo apt install meson 34 | 35 | # Build 36 | meson build && cd build 37 | ninja 38 | 39 | # Install 40 | sudo ninja install 41 | ``` 42 | 43 | This will install the executable file and the metadata required to integrate with 44 | those desktops. It also installs metadata to be collected by package repositories 45 | which integrate with certain package managers for richer presentation of apps. 46 | 47 | Though not required for local use, Write.as GTK relies on our [command-line interface](https://github.com/writeas/writeas-cli) for publishing to Write.as. 48 | Install it by downloading the [latest release](https://github.com/writeas/writeas-cli/releases/latest) or, with [Go (golang)](https://golang.org) installed, running: 49 | 50 | ```bash 51 | go get github.com/writeas/writeas-cli/cmd/writeas 52 | ``` 53 | 54 | ## Packaging 55 | You can package Write.as GTK for Debian/Apt-based systems by running in this 56 | repository's root directory: 57 | 58 | dpkg-buildpackage -us -uc 59 | 60 | This'll give you a .deb file in the parent directory. 61 | -------------------------------------------------------------------------------- /USER_GUIDE.md: -------------------------------------------------------------------------------- 1 | # User Guide 2 | 3 | Write.as GTK is a lightweight, distraction-free editor for getting your thoughts down as soon as they come to you. 4 | 5 | It launches in an instant to a blank page, ready for your words. As you type, your writing is automatically saved, and will be there waiting for you every time you open the app. If you want to share your writing, you can anonymously publish it to Write.as, where you'll get a simple URL you can share on social media, in an email, or anywhere else. 6 | 7 | [Write.as](https://write.as) is a simple, privacy-focused blogging platform that lets you publish without ever signing up. There's no ads, no tracking you around the web, and no profiting from your personal data. It's a space where you can write freely, for free, without worrying about who's watching. 8 | 9 | ## Writing 10 | 11 | Write.as GTK automatically saves your writing as you type, so you don't have to worry about losing your data (see [File locations](#file-locations) for where the draft is stored). 12 | 13 | ## Customizing the editor 14 | 15 | **Font**. Change this by selecting from the _Document font_ menu in the top-left corner of the window. You can choose between three fonts: Serif (Lora), Sans-serif (Open Sans), or Monospace (Hack). The selected font will determine how text looks while you write, as well as what the post looks like when published on Write.as. 16 | 17 | **Text size**. Change this by pressing Ctrl and + or - to increase or decrease the text size, respectively. This only affects the appearance of the editor, and not posts published on Write.as. 18 | 19 | **Dark mode**. When a desktop theme defines a dark mode, you can change into it by clicking the _Dark mode_ button in the top-right corner of the editor, next to the _Publish_ button -- or by pressing Ctrl + T. This only affects the appearance of the editor, and not posts published on Write.as. 20 | 21 | ## Keyboard shortcuts 22 | 23 | | Shortcut | Command | 24 | | -------- | ------- | 25 | | Ctrl + T | Toggle light / dark theme (where supported) | 26 | | Ctrl + - | Decrease text size | 27 | | Ctrl + + | Increase text size | 28 | | Ctrl + S | Save file as... | 29 | | Ctrl + Enter | Publish file to Write.as | 30 | 31 | **Standard shortcuts** 32 | 33 | | Shortcut | Command | 34 | | -------- | ------- | 35 | | Ctrl + A | Select all | 36 | | Ctrl + C | Copy | 37 | | Ctrl + X | Cut | 38 | | Ctrl + V | Paste | 39 | | Ctrl + Z | Undo | 40 | | Ctrl + Shift + Z | Redo | 41 | | Ctrl + W / Q | Quit | 42 | | F11 | Full-screen | 43 | 44 | ## Publishing to Write.as 45 | 46 | Write.as GTK lets you share what you've written with anyone by publishing to [Write.as](https://write.as). 47 | Once you've finished writing, press the _Publish_ button in the top-right corner of the editor (or press Ctrl + Enter) to publish your post. 48 | Your browser will open to the post on Write.as, and its URL will be copied to your clipboard so you can paste it wherever you want to share it. 49 | Behind the scenes, the CLI will store the special information needed to edit or delete the post in the future (see [Managing posts](#managing-posts) below for how to do this). 50 | 51 | After the post is published, you can press Ctrl + S to permanently save the file on your computer, or delete everything in the file to start fresh. 52 | 53 | ## Managing posts 54 | 55 | Published posts are managed by [writeas-cli](https://github.com/writeas/writeas-cli). See its [User Guide](https://github.com/writeas/writeas-cli/blob/master/GUIDE.md) for how to update and delete posts on Write.as via the command-line. 56 | 57 | ## File locations 58 | 59 | Files from the GTK app are stored in the same folder that the CLI uses: `~/.writeas` 60 | 61 | Your auto-saved draft is located at: `~/.writeas/draft.txt` 62 | 63 | Preferences for the appearance of the editor and publishing settings are stored here: `~/.writeas/prefs.ini` 64 | -------------------------------------------------------------------------------- /data/icons/128/writeas-gtk.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/writeas/writeas-gtk/4a96bf21e051293af68a83c3ef1ffbf0b7653256/data/icons/128/writeas-gtk.png -------------------------------------------------------------------------------- /data/icons/16/writeas-gtk.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/writeas/writeas-gtk/4a96bf21e051293af68a83c3ef1ffbf0b7653256/data/icons/16/writeas-gtk.png -------------------------------------------------------------------------------- /data/icons/24/writeas-gtk.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/writeas/writeas-gtk/4a96bf21e051293af68a83c3ef1ffbf0b7653256/data/icons/24/writeas-gtk.png -------------------------------------------------------------------------------- /data/icons/32/writeas-gtk.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/writeas/writeas-gtk/4a96bf21e051293af68a83c3ef1ffbf0b7653256/data/icons/32/writeas-gtk.png -------------------------------------------------------------------------------- /data/icons/48/writeas-gtk.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/writeas/writeas-gtk/4a96bf21e051293af68a83c3ef1ffbf0b7653256/data/icons/48/writeas-gtk.png -------------------------------------------------------------------------------- /data/icons/64/writeas-gtk.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/writeas/writeas-gtk/4a96bf21e051293af68a83c3ef1ffbf0b7653256/data/icons/64/writeas-gtk.png -------------------------------------------------------------------------------- /data/meson.build: -------------------------------------------------------------------------------- 1 | icon_sizes = ['16', '24', '32', '48', '64', '128'] 2 | 3 | foreach i : icon_sizes 4 | install_data( 5 | join_paths('icons', i, meson.project_name() + '.png'), 6 | install_dir: join_paths(get_option('datadir'), 'icons', 'hicolor', i + 'x' + i, 'apps'), 7 | rename: '@0@.png'.format(app_id) 8 | ) 9 | endforeach 10 | 11 | data_conf = configuration_data() 12 | data_conf.set('app_id', app_id) 13 | configure_file( 14 | input: 'writeas-gtk.desktop.in', 15 | output: '@0@.desktop'.format(app_id), 16 | configuration: data_conf, 17 | install_dir: join_paths(get_option('datadir'), 'applications') 18 | ) 19 | configure_file( 20 | input: 'writeas-gtk.appdata.xml.in', 21 | output: '@0@.appdata.xml'.format(app_id), 22 | configuration: data_conf, 23 | install_dir: join_paths(get_option('datadir'), 'metainfo') 24 | ) 25 | -------------------------------------------------------------------------------- /data/writeas-gtk.appdata.xml.in: -------------------------------------------------------------------------------- 1 | 2 | 3 | @app_id@ 4 | GPL-3.0+ 5 | CC0 6 | Write.as 7 | Publish a thought in seconds 8 | 9 | 10 |

Write.as is a simple writing tool and publishing platform. There's no sign up — just open the app, write something, and publish.

11 |

Published posts get a secret, unique link on Write.as that you can share with anyone, or keep to yourself. In either case, you remain private because we don't collect personal information about you.

12 | 22 |
23 | 24 | Write.as 25 | https://write.as/ 26 | https://write.as/contact 27 | https://github.com/writeas/writeas-gtk/issues 28 | hello@write.as 29 | 30 | 31 | @app_id@ 32 | 33 | 34 | 35 | 36 | The Write.as editor. 37 | https://write.as/img/screens/gtk/serif.png 38 | 39 | 40 | The Write.as editor in dark mode. 41 | https://write.as/img/screens/gtk/serif-dark.png 42 | 43 | 44 | https://write.as/img/screens/gtk/sans.png 45 | 46 | 47 | https://write.as/img/screens/gtk/monospace.png 48 | 49 | 50 | 51 | none 52 | none 53 | none 54 | none 55 | none 56 | none 57 | none 58 | none 59 | none 60 | none 61 | none 62 | none 63 | none 64 | none 65 | none 66 | none 67 | none 68 | none 69 | none 70 | none 71 | none 72 | moderate 73 | none 74 | none 75 | none 76 | none 77 | none 78 | 79 | 80 | 81 | 82 |

This update fixes a few minor visual issues.

83 |
    84 |
  • Fix black bar that appears in the editor on elementary OS
  • 85 |
  • Fix currently-selected font not reflected in menu when app first loads
  • 86 |
87 |
88 |
89 | 90 | 91 |

GTK updates and fixes.

92 |
    93 |
  • Fix fonts, padding, cursor color
  • 94 |
  • Increase the default font size
  • 95 |
96 |
97 |
98 | 99 | 100 |

Initial release

101 |
    102 |
  • Auto-saving single draft
  • 103 |
  • Dark mode on platforms that support it
  • 104 |
  • Choose between three fonts
  • 105 |
  • Save draft as another file
  • 106 |
  • Publish anonymously to Write.as
  • 107 |
108 |
109 |
110 |
111 | 112 | 25 113 | 114 |
115 | -------------------------------------------------------------------------------- /data/writeas-gtk.desktop.in: -------------------------------------------------------------------------------- 1 | [Desktop Entry] 2 | Type=Application 3 | Name=Write.as 4 | Comment=Publish a thought in seconds. 5 | Exec=@app_id@ 6 | Icon=@app_id@ 7 | Terminal=false 8 | MimeType= 9 | Categories=GTK;Office;Publishing; 10 | Keywords=blog;text;editor;publish; 11 | StartupNotify=true 12 | 13 | -------------------------------------------------------------------------------- /debian/changelog: -------------------------------------------------------------------------------- 1 | writeas-gtk (1.0.2-3) xenial; urgency=medium 2 | 3 | * Fix black bar that appears in the editor on elementary OS 4 | * Fix currently-selected font not reflected in menu when app first loads 5 | 6 | -- Write.as Thu, 20 Dec 2018 14:20:45 -0500 7 | 8 | writeas-gtk (1.0.1-2) xenial; urgency=medium 9 | 10 | * Fix fonts, padding, cursor color 11 | * Increase the default font size 12 | 13 | -- Write.as Fri, 14 Dec 2018 15:22:09 -0500 14 | 15 | writeas-gtk (1.0.0-1) xenial; urgency=medium 16 | 17 | * Initial Release. 18 | 19 | -- Write.as Mon, 1 Oct 2018 13:23:25 -0400 20 | -------------------------------------------------------------------------------- /debian/compat: -------------------------------------------------------------------------------- 1 | 9 2 | -------------------------------------------------------------------------------- /debian/control: -------------------------------------------------------------------------------- 1 | Source: com.github.writeas.writeas-gtk 2 | Section: x11 3 | Priority: extra 4 | Maintainer: Write.as 5 | Build-Depends: meson, 6 | debhelper (>= 9), 7 | libgtk-3-dev, 8 | libgtksourceview-3.0-dev, 9 | valac (>= 0.36), 10 | golang-go, 11 | gb 12 | Standards-Version: 3.9.3 13 | 14 | Package: com.github.writeas.writeas-gtk 15 | Architecture: any 16 | Depends: ${misc:Depends}, ${shlibs:Depends} 17 | Recommends: fonts-open-sans, fonts-hack-ttf 18 | Description: A distraction free and private writing tool, with built-in publishing. 19 | -------------------------------------------------------------------------------- /debian/copyright: -------------------------------------------------------------------------------- 1 | Format: http://dep.debian.net/deps/dep5 2 | Upstream-Name: com.github.writeas.writeas-gtk 3 | Source: https://code.as/writeas/writeas-gtk/ 4 | 5 | Files: * 6 | Copyright: 2018 A Bunch Tell LLC 7 | License: GPL-3.0+ 8 | 9 | License: GPL-3.0+ 10 | This program is free software: you can redistribute it and/or modify 11 | it under the terms of the GNU General Public License as published by 12 | the Free Software Foundation, either version 3 of the License, or 13 | (at your option) any later version. 14 | . 15 | This package is distributed in the hope that it will be useful, 16 | but WITHOUT ANY WARRANTY; without even the implied warranty of 17 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 | GNU General Public License for more details. 19 | . 20 | You should have received a copy of the GNU General Public License 21 | along with this program. If not, see . 22 | . 23 | On Debian systems, the complete text of the GNU General 24 | Public License version 3 can be found in "/usr/share/common-licenses/GPL-3". 25 | 26 | -------------------------------------------------------------------------------- /debian/rules: -------------------------------------------------------------------------------- 1 | #!/usr/bin/make -f 2 | # -*- makefile -*- 3 | # Sample debian/rules that uses debhelper. 4 | # This file was originally written by Joey Hess and Craig Small. 5 | # As a special exception, when this file is copied by dh-make into a 6 | # dh-make output file, you may use that output file without restriction. 7 | # This special exception was added by Craig Small in version 0.37 of dh-make. 8 | 9 | # This file was extended to incorporate a Meson/Ninja build system. 10 | 11 | # Uncomment this to turn on verbose mode. 12 | #export DH_VERBOSE=1 13 | 14 | %: 15 | dh $@ 16 | 17 | override_dh_auto_clean: 18 | rm -rf debian/build 19 | 20 | override_dh_auto_configure: 21 | mkdir -p debian/build 22 | cd debian/build && meson --prefix=/usr ../.. -Dplatform=elementary 23 | 24 | override_dh_auto_build: 25 | cd debian/build && ninja -v && ninja build 26 | 27 | override_dh_auto_test: 28 | cd debian/build && ninja test 29 | 30 | override_dh_auto_install: 31 | cd debian/build && DESTDIR=${CURDIR}/debian/com.github.writeas.writeas-gtk ninja install 32 | mkdir -p debian/com.github.writeas.writeas-gtk/usr/bin 33 | cp bin/writeas debian/com.github.writeas.writeas-gtk/usr/bin/ 34 | -------------------------------------------------------------------------------- /debian/source/format: -------------------------------------------------------------------------------- 1 | 3.0 (native) 2 | -------------------------------------------------------------------------------- /meson.build: -------------------------------------------------------------------------------- 1 | project('writeas-gtk', ['vala', 'c'], 2 | version: '1.0.2', 3 | license: 'GPL', 4 | meson_version: '>=0.46.0') 5 | 6 | i18n = import('i18n') 7 | 8 | build_platform = get_option('platform') 9 | if build_platform == 'elementary' 10 | app_id = 'com.github.writeas.writeas-gtk' 11 | else 12 | app_id = 'writeas-gtk' 13 | endif 14 | 15 | conf = configuration_data() 16 | conf.set_quoted('GETTEXT_PACKAGE', app_id) 17 | conf.set_quoted('APP_ID', app_id) 18 | conf.set_quoted('BUILD_PLATFORM', build_platform) 19 | config_h = configure_file(output: 'config.h', configuration: conf) 20 | config_h_dir = include_directories('.') 21 | 22 | run_target('build', command: 'meson/build-cli.sh') 23 | 24 | subdir('data') 25 | subdir('src') 26 | subdir('fonts/lora') 27 | 28 | meson.add_install_script('meson/post_install.py') 29 | 30 | -------------------------------------------------------------------------------- /meson/build-cli.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | exec_name=writeas 4 | 5 | echo "Building $exec_name CLI..." 6 | gb build github.com/writeas/writeas-cli/cmd/writeas && 7 | echo "Success." 8 | -------------------------------------------------------------------------------- /meson/post_install.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | import os 4 | import subprocess 5 | 6 | prefix = os.environ.get('MESON_INSTALL_PREFIX', '/usr/local') 7 | datadir = os.path.join(prefix, 'share') 8 | 9 | # Packaging tools define DESTDIR and this isn't needed for them 10 | if 'DESTDIR' not in os.environ: 11 | print('Updating icon cache...') 12 | icon_cache_dir = os.path.join(datadir, 'icons', 'hicolor') 13 | if not os.path.exists(icon_cache_dir): 14 | os.makedirs(icon_cache_dir) 15 | subprocess.call(['gtk-update-icon-cache', '-qtf', icon_cache_dir]) 16 | 17 | print('Updating desktop database...') 18 | desktop_database_dir = os.path.join(datadir, 'applications') 19 | if not os.path.exists(desktop_database_dir): 20 | os.makedirs(desktop_database_dir) 21 | subprocess.call(['update-desktop-database', '-q', desktop_database_dir]) 22 | 23 | -------------------------------------------------------------------------------- /meson_options.txt: -------------------------------------------------------------------------------- 1 | option('platform', type: 'combo', choices: ['default', 'elementary'], value: 'default') 2 | -------------------------------------------------------------------------------- /screenshot-monospace.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/writeas/writeas-gtk/4a96bf21e051293af68a83c3ef1ffbf0b7653256/screenshot-monospace.png -------------------------------------------------------------------------------- /screenshot-sans-light.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/writeas/writeas-gtk/4a96bf21e051293af68a83c3ef1ffbf0b7653256/screenshot-sans-light.png -------------------------------------------------------------------------------- /screenshot-serif-dark.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/writeas/writeas-gtk/4a96bf21e051293af68a83c3ef1ffbf0b7653256/screenshot-serif-dark.png -------------------------------------------------------------------------------- /screenshot-serif-light.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/writeas/writeas-gtk/4a96bf21e051293af68a83c3ef1ffbf0b7653256/screenshot-serif-light.png -------------------------------------------------------------------------------- /src/Granite/Accels.vala: -------------------------------------------------------------------------------- 1 | // From https://github.com/elementary/granite/blob/621f2669f6c8940fe32ac9817ddca92e97d27ae0/lib/Widgets/Utils.vala#L79-L192 2 | 3 | /* 4 | * Copyright (C) 2012-2017 Granite Developers 5 | * 6 | * This program or library is free software; you can redistribute it 7 | * and/or modify it under the terms of the GNU Lesser General Public 8 | * License as published by the Free Software Foundation; either 9 | * version 3 of the License, or (at your option) any later version. 10 | * 11 | * This library is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 | * Lesser General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU Lesser General 17 | * Public License along with this library; if not, write to the 18 | * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 19 | * Boston, MA 02110-1301 USA. 20 | */ 21 | 22 | namespace Granite { 23 | 24 | /** 25 | * Converts a {@link Gtk.accelerator_parse} style accel string to a human-readable string. 26 | * 27 | * @param accel an accelerator label like “a” or “Right” 28 | * 29 | * @return a human-readable string like "Ctrl + A" or "⌘ + →" 30 | */ 31 | public static string accel_to_string (string accel) { 32 | uint accel_key; 33 | Gdk.ModifierType accel_mods; 34 | Gtk.accelerator_parse (accel, out accel_key, out accel_mods); 35 | 36 | string[] arr = {}; 37 | if (Gdk.ModifierType.SUPER_MASK in accel_mods) { 38 | arr += "⌘"; 39 | } 40 | 41 | if (Gdk.ModifierType.SHIFT_MASK in accel_mods) { 42 | arr += _("Shift"); 43 | } 44 | 45 | if (Gdk.ModifierType.CONTROL_MASK in accel_mods) { 46 | arr += _("Ctrl"); 47 | } 48 | 49 | if (Gdk.ModifierType.MOD1_MASK in accel_mods) { 50 | arr += _("Alt"); 51 | } 52 | 53 | switch (accel_key) { 54 | case Gdk.Key.Up: 55 | arr += "↑"; 56 | break; 57 | case Gdk.Key.Down: 58 | arr += "↓"; 59 | break; 60 | case Gdk.Key.Left: 61 | arr += "←"; 62 | break; 63 | case Gdk.Key.Right: 64 | arr += "→"; 65 | break; 66 | case Gdk.Key.minus: 67 | case Gdk.Key.KP_Subtract: 68 | ///TRANSLATORS: This is a non-symbol representation of the "-" key 69 | arr += _("Minus"); 70 | break; 71 | case Gdk.Key.KP_Add: 72 | case Gdk.Key.plus: 73 | ///TRANSLATORS: This is a non-symbol representation of the "+" key 74 | arr += _("Plus"); 75 | break; 76 | case Gdk.Key.KP_Enter: 77 | case Gdk.Key.Return: 78 | arr += _("Enter"); 79 | break; 80 | default: 81 | arr += Gtk.accelerator_get_label (accel_key, 0); 82 | break; 83 | } 84 | 85 | return string.joinv (" + ", arr); 86 | } 87 | 88 | /** 89 | * Takes a description and an array of accels and returns {@link Pango} markup for use in a {@link Gtk.Tooltip}. This method uses {@link Granite.accel_to_string}. 90 | * 91 | * Example: 92 | * 93 | * Description 94 | * Shortcut 1, Shortcut 2 95 | * 96 | * @param a string array of accelerator labels like {"a", "Right"} 97 | * 98 | * @param description a standard tooltip text string 99 | * 100 | * @return {@link Pango} markup with the description label on one line and a list of human-readable accels on a new line 101 | */ 102 | public static string markup_accel_tooltip (string[]? accels, string? description = null) { 103 | string[] parts = {}; 104 | if (description != null && description != "") { 105 | parts += description; 106 | } 107 | 108 | if (accels != null && accels.length > 0) { 109 | string[] unique_accels = {}; 110 | 111 | for (int i = 0; i < accels.length; i++) { 112 | if (accels[i] == "") { 113 | continue; 114 | } 115 | 116 | var accel_string = accel_to_string (accels[i]); 117 | if (!(accel_string in unique_accels)) { 118 | unique_accels += accel_string; 119 | } 120 | } 121 | 122 | if (unique_accels.length > 0) { 123 | ///TRANSLATORS: This is a delimiter that separates two keyboard shortcut labels like "⌘ + →, Control + A" 124 | var accel_label = string.joinv (_(", "), unique_accels); 125 | 126 | var accel_markup = """%s""".printf (accel_label); 127 | 128 | parts += accel_markup; 129 | } 130 | } 131 | 132 | return string.joinv ("\n", parts); 133 | } 134 | 135 | } 136 | 137 | -------------------------------------------------------------------------------- /src/Granite/ModeSwitch.vala: -------------------------------------------------------------------------------- 1 | // From https://github.com/elementary/granite/blob/2066b377226cf327cb2d5399b6b40a2d36d47b11/lib/Widgets/ModeSwitch.vala 2 | 3 | /* 4 | * Copyright (c) 2018 elementary, Inc. (https://elementary.io) 5 | * 6 | * This program is free software; you can redistribute it and/or 7 | * modify it under the terms of the GNU General Public 8 | * License as published by the Free Software Foundation; either 9 | * version 2 of the License, or (at your option) any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 | * General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public 17 | * License along with this program; if not, write to the 18 | * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 19 | * Boston, MA 02110-1301 USA 20 | */ 21 | 22 | /** 23 | * ModeSwitch is a selection control for choosing between two options that can be described with an icon. 24 | * 25 | * ''Example''<
> 26 | * {{{ 27 | * var gtk_settings = Gtk.Settings.get_default (); 28 | * 29 | * var mode_switch = new ModeSwitch.from_icon_name ("display-brightness-symbolic", "weather-clear-night-symbolic"); 30 | * mode_switch.primary_icon_tooltip_text = _("Light background"); 31 | * mode_switch.secondary_icon_tooltip_text = _("Dark background"); 32 | * mode_switch.bind_property ("active", gtk_settings, "gtk_application_prefer_dark_theme"); 33 | * }}} 34 | */ 35 | public class Granite.ModeSwitch : Gtk.Grid { 36 | /** 37 | * Whether the {@link Gtk.Switch} widget is pointing to the secondary icon or not. 38 | */ 39 | public bool active { get; set; } 40 | 41 | /** 42 | * The {@link GLib.Icon} to use for the primary icon for the switch. 43 | */ 44 | public GLib.Icon primary_icon_gicon { get; construct set; } 45 | 46 | /** 47 | * The icon name to use for the primary icon for the switch. 48 | */ 49 | public string primary_icon_name { get; construct set; } 50 | 51 | /** 52 | * The contents of the tooltip on the primary icon. 53 | */ 54 | public string primary_icon_tooltip_text { get; set; } 55 | 56 | /** 57 | * The {@link GLib.Icon} to use for the secondary icon for the switch. 58 | */ 59 | public GLib.Icon secondary_icon_gicon { get; construct set; } 60 | 61 | /** 62 | * The icon name to use for the secondary icon for the switch. 63 | */ 64 | public string secondary_icon_name { get; construct set; } 65 | 66 | /** 67 | * The contents of the tooltip on the secondary icon. 68 | */ 69 | public string secondary_icon_tooltip_text { get; set; } 70 | 71 | /** 72 | * Constructs a new {@link Granite.ModeSwitch} using {@link GLib.Icon}s. 73 | * 74 | * @param primary_icon_gicon The {@link GLib.Icon} to use for the primary icon for the switch. 75 | * @param secondary_icon_gicon The {@link GLib.Icon} to use for the secondary icon for the switch. 76 | */ 77 | public ModeSwitch (GLib.Icon primary_icon_gicon, GLib.Icon secondary_icon_gicon) { 78 | Object ( 79 | primary_icon_gicon: primary_icon_gicon, 80 | secondary_icon_gicon: secondary_icon_gicon 81 | ); 82 | } 83 | 84 | /** 85 | * Constructs a new {@link Granite.ModeSwitch} from icon names. 86 | * 87 | * @param primary_icon_name The icon name to use for the primary icon for the switch. 88 | * @param secondary_icon_name The icon name to use for the secondary icon for the switch. 89 | */ 90 | public ModeSwitch.from_icon_name (string primary_icon_name, string secondary_icon_name) { 91 | Object ( 92 | primary_icon_gicon: new ThemedIcon (primary_icon_name), 93 | secondary_icon_gicon: new ThemedIcon (secondary_icon_name), 94 | primary_icon_name: primary_icon_name, 95 | secondary_icon_name: secondary_icon_name 96 | ); 97 | } 98 | 99 | construct { 100 | var primary_image = new Gtk.Image (); 101 | primary_image.pixel_size = 16; 102 | 103 | var primary_icon_box = new Gtk.EventBox (); 104 | primary_icon_box.add_events (Gdk.EventMask.BUTTON_RELEASE_MASK); 105 | primary_icon_box.add (primary_image); 106 | 107 | var mode_switch = new Gtk.Switch (); 108 | mode_switch.valign = Gtk.Align.CENTER; 109 | mode_switch.get_style_context ().add_class ("mode-switch"); 110 | 111 | var secondary_icon = new Gtk.Image (); 112 | secondary_icon.pixel_size = 16; 113 | 114 | var secondary_icon_box = new Gtk.EventBox (); 115 | secondary_icon_box.add_events (Gdk.EventMask.BUTTON_RELEASE_MASK); 116 | secondary_icon_box.add (secondary_icon); 117 | 118 | column_spacing = 6; 119 | add (primary_icon_box); 120 | add (mode_switch); 121 | add (secondary_icon_box); 122 | 123 | bind_property ("primary-icon-gicon", primary_image, "gicon", GLib.BindingFlags.SYNC_CREATE); 124 | bind_property ("primary-icon-name", primary_image, "icon-name", GLib.BindingFlags.SYNC_CREATE); 125 | bind_property ("primary-icon-tooltip-text", primary_image, "tooltip-text"); 126 | bind_property ("secondary-icon-gicon", secondary_icon, "gicon", GLib.BindingFlags.SYNC_CREATE); 127 | bind_property ("secondary-icon-name", secondary_icon, "icon_name", GLib.BindingFlags.SYNC_CREATE); 128 | bind_property ("secondary-icon-tooltip-text", secondary_icon, "tooltip-text"); 129 | 130 | this.notify["active"].connect (() => { 131 | if (Gtk.StateFlags.DIR_RTL in get_state_flags ()) { 132 | mode_switch.active = !active; 133 | } else { 134 | mode_switch.active = active; 135 | } 136 | }); 137 | 138 | mode_switch.notify["active"].connect (() => { 139 | if (Gtk.StateFlags.DIR_RTL in get_state_flags ()) { 140 | active = !mode_switch.active; 141 | } else { 142 | active = mode_switch.active; 143 | } 144 | }); 145 | 146 | primary_icon_box.button_release_event.connect (() => { 147 | active = false; 148 | return Gdk.EVENT_STOP; 149 | }); 150 | 151 | secondary_icon_box.button_release_event.connect (() => { 152 | active = true; 153 | return Gdk.EVENT_STOP; 154 | }); 155 | } 156 | } 157 | 158 | -------------------------------------------------------------------------------- /src/application.vala: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright © 2018 Write.as 3 | 4 | This file is part of the Write.as GTK desktop app. 5 | 6 | This program is free software: you can redistribute it and/or modify 7 | it under the terms of the GNU General Public License as published by 8 | the Free Software Foundation, either version 3 of the License, or 9 | (at your option) any later version. 10 | 11 | This program is distributed in the hope that it will be useful, 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | GNU General Public License for more details. 15 | 16 | You should have received a copy of the GNU General Public License 17 | along with this program. If not, see . 18 | */ 19 | 20 | extern const string APP_ID; 21 | extern const string BUILD_PLATFORM; 22 | 23 | public class WriteAs.Application : Gtk.Application { 24 | construct { 25 | this.flags |= ApplicationFlags.HANDLES_OPEN; 26 | Intl.setlocale(LocaleCategory.ALL, ""); 27 | Intl.textdomain("write.as"); 28 | 29 | application_id = APP_ID + ".desktop"; 30 | } 31 | 32 | public override void activate() { 33 | if (get_windows().length() == 0) 34 | new WriteAs.MainWindow(this).show_all(); 35 | } 36 | 37 | public override void open(File[] files, string hint) { 38 | activate(); // ensure we have a window open. 39 | } 40 | 41 | public static int main(string[] args) { 42 | return new WriteAs.Application().run(args); 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /src/github.com/BurntSushi/toml/COMPATIBLE: -------------------------------------------------------------------------------- 1 | Compatible with TOML version 2 | [v0.4.0](https://github.com/toml-lang/toml/blob/v0.4.0/versions/en/toml-v0.4.0.md) 3 | 4 | -------------------------------------------------------------------------------- /src/github.com/BurntSushi/toml/COPYING: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2013 TOML authors 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 13 | all 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 21 | THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /src/github.com/BurntSushi/toml/Makefile: -------------------------------------------------------------------------------- 1 | install: 2 | go install ./... 3 | 4 | test: install 5 | go test -v 6 | toml-test toml-test-decoder 7 | toml-test -encoder toml-test-encoder 8 | 9 | fmt: 10 | gofmt -w *.go */*.go 11 | colcheck *.go */*.go 12 | 13 | tags: 14 | find ./ -name '*.go' -print0 | xargs -0 gotags > TAGS 15 | 16 | push: 17 | git push origin master 18 | git push github master 19 | 20 | -------------------------------------------------------------------------------- /src/github.com/BurntSushi/toml/README.md: -------------------------------------------------------------------------------- 1 | ## TOML parser and encoder for Go with reflection 2 | 3 | TOML stands for Tom's Obvious, Minimal Language. This Go package provides a 4 | reflection interface similar to Go's standard library `json` and `xml` 5 | packages. This package also supports the `encoding.TextUnmarshaler` and 6 | `encoding.TextMarshaler` interfaces so that you can define custom data 7 | representations. (There is an example of this below.) 8 | 9 | Spec: https://github.com/toml-lang/toml 10 | 11 | Compatible with TOML version 12 | [v0.4.0](https://github.com/toml-lang/toml/blob/master/versions/en/toml-v0.4.0.md) 13 | 14 | Documentation: https://godoc.org/github.com/BurntSushi/toml 15 | 16 | Installation: 17 | 18 | ```bash 19 | go get github.com/BurntSushi/toml 20 | ``` 21 | 22 | Try the toml validator: 23 | 24 | ```bash 25 | go get github.com/BurntSushi/toml/cmd/tomlv 26 | tomlv some-toml-file.toml 27 | ``` 28 | 29 | [![Build Status](https://travis-ci.org/BurntSushi/toml.svg?branch=master)](https://travis-ci.org/BurntSushi/toml) [![GoDoc](https://godoc.org/github.com/BurntSushi/toml?status.svg)](https://godoc.org/github.com/BurntSushi/toml) 30 | 31 | ### Testing 32 | 33 | This package passes all tests in 34 | [toml-test](https://github.com/BurntSushi/toml-test) for both the decoder 35 | and the encoder. 36 | 37 | ### Examples 38 | 39 | This package works similarly to how the Go standard library handles `XML` 40 | and `JSON`. Namely, data is loaded into Go values via reflection. 41 | 42 | For the simplest example, consider some TOML file as just a list of keys 43 | and values: 44 | 45 | ```toml 46 | Age = 25 47 | Cats = [ "Cauchy", "Plato" ] 48 | Pi = 3.14 49 | Perfection = [ 6, 28, 496, 8128 ] 50 | DOB = 1987-07-05T05:45:00Z 51 | ``` 52 | 53 | Which could be defined in Go as: 54 | 55 | ```go 56 | type Config struct { 57 | Age int 58 | Cats []string 59 | Pi float64 60 | Perfection []int 61 | DOB time.Time // requires `import time` 62 | } 63 | ``` 64 | 65 | And then decoded with: 66 | 67 | ```go 68 | var conf Config 69 | if _, err := toml.Decode(tomlData, &conf); err != nil { 70 | // handle error 71 | } 72 | ``` 73 | 74 | You can also use struct tags if your struct field name doesn't map to a TOML 75 | key value directly: 76 | 77 | ```toml 78 | some_key_NAME = "wat" 79 | ``` 80 | 81 | ```go 82 | type TOML struct { 83 | ObscureKey string `toml:"some_key_NAME"` 84 | } 85 | ``` 86 | 87 | ### Using the `encoding.TextUnmarshaler` interface 88 | 89 | Here's an example that automatically parses duration strings into 90 | `time.Duration` values: 91 | 92 | ```toml 93 | [[song]] 94 | name = "Thunder Road" 95 | duration = "4m49s" 96 | 97 | [[song]] 98 | name = "Stairway to Heaven" 99 | duration = "8m03s" 100 | ``` 101 | 102 | Which can be decoded with: 103 | 104 | ```go 105 | type song struct { 106 | Name string 107 | Duration duration 108 | } 109 | type songs struct { 110 | Song []song 111 | } 112 | var favorites songs 113 | if _, err := toml.Decode(blob, &favorites); err != nil { 114 | log.Fatal(err) 115 | } 116 | 117 | for _, s := range favorites.Song { 118 | fmt.Printf("%s (%s)\n", s.Name, s.Duration) 119 | } 120 | ``` 121 | 122 | And you'll also need a `duration` type that satisfies the 123 | `encoding.TextUnmarshaler` interface: 124 | 125 | ```go 126 | type duration struct { 127 | time.Duration 128 | } 129 | 130 | func (d *duration) UnmarshalText(text []byte) error { 131 | var err error 132 | d.Duration, err = time.ParseDuration(string(text)) 133 | return err 134 | } 135 | ``` 136 | 137 | ### More complex usage 138 | 139 | Here's an example of how to load the example from the official spec page: 140 | 141 | ```toml 142 | # This is a TOML document. Boom. 143 | 144 | title = "TOML Example" 145 | 146 | [owner] 147 | name = "Tom Preston-Werner" 148 | organization = "GitHub" 149 | bio = "GitHub Cofounder & CEO\nLikes tater tots and beer." 150 | dob = 1979-05-27T07:32:00Z # First class dates? Why not? 151 | 152 | [database] 153 | server = "192.168.1.1" 154 | ports = [ 8001, 8001, 8002 ] 155 | connection_max = 5000 156 | enabled = true 157 | 158 | [servers] 159 | 160 | # You can indent as you please. Tabs or spaces. TOML don't care. 161 | [servers.alpha] 162 | ip = "10.0.0.1" 163 | dc = "eqdc10" 164 | 165 | [servers.beta] 166 | ip = "10.0.0.2" 167 | dc = "eqdc10" 168 | 169 | [clients] 170 | data = [ ["gamma", "delta"], [1, 2] ] # just an update to make sure parsers support it 171 | 172 | # Line breaks are OK when inside arrays 173 | hosts = [ 174 | "alpha", 175 | "omega" 176 | ] 177 | ``` 178 | 179 | And the corresponding Go types are: 180 | 181 | ```go 182 | type tomlConfig struct { 183 | Title string 184 | Owner ownerInfo 185 | DB database `toml:"database"` 186 | Servers map[string]server 187 | Clients clients 188 | } 189 | 190 | type ownerInfo struct { 191 | Name string 192 | Org string `toml:"organization"` 193 | Bio string 194 | DOB time.Time 195 | } 196 | 197 | type database struct { 198 | Server string 199 | Ports []int 200 | ConnMax int `toml:"connection_max"` 201 | Enabled bool 202 | } 203 | 204 | type server struct { 205 | IP string 206 | DC string 207 | } 208 | 209 | type clients struct { 210 | Data [][]interface{} 211 | Hosts []string 212 | } 213 | ``` 214 | 215 | Note that a case insensitive match will be tried if an exact match can't be 216 | found. 217 | 218 | A working example of the above can be found in `_examples/example.{go,toml}`. 219 | -------------------------------------------------------------------------------- /src/github.com/BurntSushi/toml/_examples/example.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "time" 6 | 7 | "github.com/BurntSushi/toml" 8 | ) 9 | 10 | type tomlConfig struct { 11 | Title string 12 | Owner ownerInfo 13 | DB database `toml:"database"` 14 | Servers map[string]server 15 | Clients clients 16 | } 17 | 18 | type ownerInfo struct { 19 | Name string 20 | Org string `toml:"organization"` 21 | Bio string 22 | DOB time.Time 23 | } 24 | 25 | type database struct { 26 | Server string 27 | Ports []int 28 | ConnMax int `toml:"connection_max"` 29 | Enabled bool 30 | } 31 | 32 | type server struct { 33 | IP string 34 | DC string 35 | } 36 | 37 | type clients struct { 38 | Data [][]interface{} 39 | Hosts []string 40 | } 41 | 42 | func main() { 43 | var config tomlConfig 44 | if _, err := toml.DecodeFile("example.toml", &config); err != nil { 45 | fmt.Println(err) 46 | return 47 | } 48 | 49 | fmt.Printf("Title: %s\n", config.Title) 50 | fmt.Printf("Owner: %s (%s, %s), Born: %s\n", 51 | config.Owner.Name, config.Owner.Org, config.Owner.Bio, 52 | config.Owner.DOB) 53 | fmt.Printf("Database: %s %v (Max conn. %d), Enabled? %v\n", 54 | config.DB.Server, config.DB.Ports, config.DB.ConnMax, 55 | config.DB.Enabled) 56 | for serverName, server := range config.Servers { 57 | fmt.Printf("Server: %s (%s, %s)\n", serverName, server.IP, server.DC) 58 | } 59 | fmt.Printf("Client data: %v\n", config.Clients.Data) 60 | fmt.Printf("Client hosts: %v\n", config.Clients.Hosts) 61 | } 62 | -------------------------------------------------------------------------------- /src/github.com/BurntSushi/toml/_examples/example.toml: -------------------------------------------------------------------------------- 1 | # This is a TOML document. Boom. 2 | 3 | title = "TOML Example" 4 | 5 | [owner] 6 | name = "Tom Preston-Werner" 7 | organization = "GitHub" 8 | bio = "GitHub Cofounder & CEO\nLikes tater tots and beer." 9 | dob = 1979-05-27T07:32:00Z # First class dates? Why not? 10 | 11 | [database] 12 | server = "192.168.1.1" 13 | ports = [ 8001, 8001, 8002 ] 14 | connection_max = 5000 15 | enabled = true 16 | 17 | [servers] 18 | 19 | # You can indent as you please. Tabs or spaces. TOML don't care. 20 | [servers.alpha] 21 | ip = "10.0.0.1" 22 | dc = "eqdc10" 23 | 24 | [servers.beta] 25 | ip = "10.0.0.2" 26 | dc = "eqdc10" 27 | 28 | [clients] 29 | data = [ ["gamma", "delta"], [1, 2] ] # just an update to make sure parsers support it 30 | 31 | # Line breaks are OK when inside arrays 32 | hosts = [ 33 | "alpha", 34 | "omega" 35 | ] 36 | -------------------------------------------------------------------------------- /src/github.com/BurntSushi/toml/_examples/hard.toml: -------------------------------------------------------------------------------- 1 | # Test file for TOML 2 | # Only this one tries to emulate a TOML file written by a user of the kind of parser writers probably hate 3 | # This part you'll really hate 4 | 5 | [the] 6 | test_string = "You'll hate me after this - #" # " Annoying, isn't it? 7 | 8 | [the.hard] 9 | test_array = [ "] ", " # "] # ] There you go, parse this! 10 | test_array2 = [ "Test #11 ]proved that", "Experiment #9 was a success" ] 11 | # You didn't think it'd as easy as chucking out the last #, did you? 12 | another_test_string = " Same thing, but with a string #" 13 | harder_test_string = " And when \"'s are in the string, along with # \"" # "and comments are there too" 14 | # Things will get harder 15 | 16 | [the.hard.bit#] 17 | what? = "You don't think some user won't do that?" 18 | multi_line_array = [ 19 | "]", 20 | # ] Oh yes I did 21 | ] 22 | 23 | -------------------------------------------------------------------------------- /src/github.com/BurntSushi/toml/_examples/implicit.toml: -------------------------------------------------------------------------------- 1 | # [x] you 2 | # [x.y] don't 3 | # [x.y.z] need these 4 | [x.y.z.w] # for this to work 5 | -------------------------------------------------------------------------------- /src/github.com/BurntSushi/toml/_examples/invalid-apples.toml: -------------------------------------------------------------------------------- 1 | # DO NOT WANT 2 | [fruit] 3 | type = "apple" 4 | 5 | [fruit.type] 6 | apple = "yes" 7 | -------------------------------------------------------------------------------- /src/github.com/BurntSushi/toml/_examples/invalid.toml: -------------------------------------------------------------------------------- 1 | # This is an INVALID TOML document. Boom. 2 | # Can you spot the error without help? 3 | 4 | title = "TOML Example" 5 | 6 | [owner] 7 | name = "Tom Preston-Werner" 8 | organization = "GitHub" 9 | bio = "GitHub Cofounder & CEO\nLikes tater tots and beer." 10 | dob = 1979-05-27T7:32:00Z # First class dates? Why not? 11 | 12 | [database] 13 | server = "192.168.1.1" 14 | ports = [ 8001, 8001, 8002 ] 15 | connection_max = 5000 16 | enabled = true 17 | 18 | [servers] 19 | # You can indent as you please. Tabs or spaces. TOML don't care. 20 | [servers.alpha] 21 | ip = "10.0.0.1" 22 | dc = "eqdc10" 23 | 24 | [servers.beta] 25 | ip = "10.0.0.2" 26 | dc = "eqdc10" 27 | 28 | [clients] 29 | data = [ ["gamma", "delta"], [1, 2] ] # just an update to make sure parsers support it 30 | 31 | # Line breaks are OK when inside arrays 32 | hosts = [ 33 | "alpha", 34 | "omega" 35 | ] 36 | -------------------------------------------------------------------------------- /src/github.com/BurntSushi/toml/_examples/readme1.toml: -------------------------------------------------------------------------------- 1 | Age = 25 2 | Cats = [ "Cauchy", "Plato" ] 3 | Pi = 3.14 4 | Perfection = [ 6, 28, 496, 8128 ] 5 | DOB = 1987-07-05T05:45:00Z 6 | -------------------------------------------------------------------------------- /src/github.com/BurntSushi/toml/_examples/readme2.toml: -------------------------------------------------------------------------------- 1 | some_key_NAME = "wat" 2 | -------------------------------------------------------------------------------- /src/github.com/BurntSushi/toml/cmd/toml-test-decoder/COPYING: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2013 TOML authors 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 13 | all 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 21 | THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /src/github.com/BurntSushi/toml/cmd/toml-test-decoder/README.md: -------------------------------------------------------------------------------- 1 | # Implements the TOML test suite interface 2 | 3 | This is an implementation of the interface expected by 4 | [toml-test](https://github.com/BurntSushi/toml-test) for my 5 | [toml parser written in Go](https://github.com/BurntSushi/toml). 6 | In particular, it maps TOML data on `stdin` to a JSON format on `stdout`. 7 | 8 | 9 | Compatible with TOML version 10 | [v0.4.0](https://github.com/toml-lang/toml/blob/master/versions/en/toml-v0.4.0.md) 11 | 12 | Compatible with `toml-test` version 13 | [v0.2.0](https://github.com/BurntSushi/toml-test/tree/v0.2.0) 14 | -------------------------------------------------------------------------------- /src/github.com/BurntSushi/toml/cmd/toml-test-decoder/main.go: -------------------------------------------------------------------------------- 1 | // Command toml-test-decoder satisfies the toml-test interface for testing 2 | // TOML decoders. Namely, it accepts TOML on stdin and outputs JSON on stdout. 3 | package main 4 | 5 | import ( 6 | "encoding/json" 7 | "flag" 8 | "fmt" 9 | "log" 10 | "os" 11 | "path" 12 | "time" 13 | 14 | "github.com/BurntSushi/toml" 15 | ) 16 | 17 | func init() { 18 | log.SetFlags(0) 19 | 20 | flag.Usage = usage 21 | flag.Parse() 22 | } 23 | 24 | func usage() { 25 | log.Printf("Usage: %s < toml-file\n", path.Base(os.Args[0])) 26 | flag.PrintDefaults() 27 | 28 | os.Exit(1) 29 | } 30 | 31 | func main() { 32 | if flag.NArg() != 0 { 33 | flag.Usage() 34 | } 35 | 36 | var tmp interface{} 37 | if _, err := toml.DecodeReader(os.Stdin, &tmp); err != nil { 38 | log.Fatalf("Error decoding TOML: %s", err) 39 | } 40 | 41 | typedTmp := translate(tmp) 42 | if err := json.NewEncoder(os.Stdout).Encode(typedTmp); err != nil { 43 | log.Fatalf("Error encoding JSON: %s", err) 44 | } 45 | } 46 | 47 | func translate(tomlData interface{}) interface{} { 48 | switch orig := tomlData.(type) { 49 | case map[string]interface{}: 50 | typed := make(map[string]interface{}, len(orig)) 51 | for k, v := range orig { 52 | typed[k] = translate(v) 53 | } 54 | return typed 55 | case []map[string]interface{}: 56 | typed := make([]map[string]interface{}, len(orig)) 57 | for i, v := range orig { 58 | typed[i] = translate(v).(map[string]interface{}) 59 | } 60 | return typed 61 | case []interface{}: 62 | typed := make([]interface{}, len(orig)) 63 | for i, v := range orig { 64 | typed[i] = translate(v) 65 | } 66 | 67 | // We don't really need to tag arrays, but let's be future proof. 68 | // (If TOML ever supports tuples, we'll need this.) 69 | return tag("array", typed) 70 | case time.Time: 71 | return tag("datetime", orig.Format("2006-01-02T15:04:05Z")) 72 | case bool: 73 | return tag("bool", fmt.Sprintf("%v", orig)) 74 | case int64: 75 | return tag("integer", fmt.Sprintf("%d", orig)) 76 | case float64: 77 | return tag("float", fmt.Sprintf("%v", orig)) 78 | case string: 79 | return tag("string", orig) 80 | } 81 | 82 | panic(fmt.Sprintf("Unknown type: %T", tomlData)) 83 | } 84 | 85 | func tag(typeName string, data interface{}) map[string]interface{} { 86 | return map[string]interface{}{ 87 | "type": typeName, 88 | "value": data, 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /src/github.com/BurntSushi/toml/cmd/toml-test-encoder/COPYING: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2013 TOML authors 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 13 | all 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 21 | THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /src/github.com/BurntSushi/toml/cmd/toml-test-encoder/README.md: -------------------------------------------------------------------------------- 1 | # Implements the TOML test suite interface for TOML encoders 2 | 3 | This is an implementation of the interface expected by 4 | [toml-test](https://github.com/BurntSushi/toml-test) for the 5 | [TOML encoder](https://github.com/BurntSushi/toml). 6 | In particular, it maps JSON data on `stdin` to a TOML format on `stdout`. 7 | 8 | 9 | Compatible with TOML version 10 | [v0.4.0](https://github.com/toml-lang/toml/blob/master/versions/en/toml-v0.4.0.md) 11 | 12 | Compatible with `toml-test` version 13 | [v0.2.0](https://github.com/BurntSushi/toml-test/tree/v0.2.0) 14 | -------------------------------------------------------------------------------- /src/github.com/BurntSushi/toml/cmd/toml-test-encoder/main.go: -------------------------------------------------------------------------------- 1 | // Command toml-test-encoder satisfies the toml-test interface for testing 2 | // TOML encoders. Namely, it accepts JSON on stdin and outputs TOML on stdout. 3 | package main 4 | 5 | import ( 6 | "encoding/json" 7 | "flag" 8 | "log" 9 | "os" 10 | "path" 11 | "strconv" 12 | "time" 13 | 14 | "github.com/BurntSushi/toml" 15 | ) 16 | 17 | func init() { 18 | log.SetFlags(0) 19 | 20 | flag.Usage = usage 21 | flag.Parse() 22 | } 23 | 24 | func usage() { 25 | log.Printf("Usage: %s < json-file\n", path.Base(os.Args[0])) 26 | flag.PrintDefaults() 27 | 28 | os.Exit(1) 29 | } 30 | 31 | func main() { 32 | if flag.NArg() != 0 { 33 | flag.Usage() 34 | } 35 | 36 | var tmp interface{} 37 | if err := json.NewDecoder(os.Stdin).Decode(&tmp); err != nil { 38 | log.Fatalf("Error decoding JSON: %s", err) 39 | } 40 | 41 | tomlData := translate(tmp) 42 | if err := toml.NewEncoder(os.Stdout).Encode(tomlData); err != nil { 43 | log.Fatalf("Error encoding TOML: %s", err) 44 | } 45 | } 46 | 47 | func translate(typedJson interface{}) interface{} { 48 | switch v := typedJson.(type) { 49 | case map[string]interface{}: 50 | if len(v) == 2 && in("type", v) && in("value", v) { 51 | return untag(v) 52 | } 53 | m := make(map[string]interface{}, len(v)) 54 | for k, v2 := range v { 55 | m[k] = translate(v2) 56 | } 57 | return m 58 | case []interface{}: 59 | tabArray := make([]map[string]interface{}, len(v)) 60 | for i := range v { 61 | if m, ok := translate(v[i]).(map[string]interface{}); ok { 62 | tabArray[i] = m 63 | } else { 64 | log.Fatalf("JSON arrays may only contain objects. This " + 65 | "corresponds to only tables being allowed in " + 66 | "TOML table arrays.") 67 | } 68 | } 69 | return tabArray 70 | } 71 | log.Fatalf("Unrecognized JSON format '%T'.", typedJson) 72 | panic("unreachable") 73 | } 74 | 75 | func untag(typed map[string]interface{}) interface{} { 76 | t := typed["type"].(string) 77 | v := typed["value"] 78 | switch t { 79 | case "string": 80 | return v.(string) 81 | case "integer": 82 | v := v.(string) 83 | n, err := strconv.Atoi(v) 84 | if err != nil { 85 | log.Fatalf("Could not parse '%s' as integer: %s", v, err) 86 | } 87 | return n 88 | case "float": 89 | v := v.(string) 90 | f, err := strconv.ParseFloat(v, 64) 91 | if err != nil { 92 | log.Fatalf("Could not parse '%s' as float64: %s", v, err) 93 | } 94 | return f 95 | case "datetime": 96 | v := v.(string) 97 | t, err := time.Parse("2006-01-02T15:04:05Z", v) 98 | if err != nil { 99 | log.Fatalf("Could not parse '%s' as a datetime: %s", v, err) 100 | } 101 | return t 102 | case "bool": 103 | v := v.(string) 104 | switch v { 105 | case "true": 106 | return true 107 | case "false": 108 | return false 109 | } 110 | log.Fatalf("Could not parse '%s' as a boolean.", v) 111 | case "array": 112 | v := v.([]interface{}) 113 | array := make([]interface{}, len(v)) 114 | for i := range v { 115 | if m, ok := v[i].(map[string]interface{}); ok { 116 | array[i] = untag(m) 117 | } else { 118 | log.Fatalf("Arrays may only contain other arrays or "+ 119 | "primitive values, but found a '%T'.", m) 120 | } 121 | } 122 | return array 123 | } 124 | log.Fatalf("Unrecognized tag type '%s'.", t) 125 | panic("unreachable") 126 | } 127 | 128 | func in(key string, m map[string]interface{}) bool { 129 | _, ok := m[key] 130 | return ok 131 | } 132 | -------------------------------------------------------------------------------- /src/github.com/BurntSushi/toml/cmd/tomlv/COPYING: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2013 TOML authors 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 13 | all 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 21 | THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /src/github.com/BurntSushi/toml/cmd/tomlv/README.md: -------------------------------------------------------------------------------- 1 | # TOML Validator 2 | 3 | If Go is installed, it's simple to try it out: 4 | 5 | ```bash 6 | go get github.com/BurntSushi/toml/cmd/tomlv 7 | tomlv some-toml-file.toml 8 | ``` 9 | 10 | You can see the types of every key in a TOML file with: 11 | 12 | ```bash 13 | tomlv -types some-toml-file.toml 14 | ``` 15 | 16 | At the moment, only one error message is reported at a time. Error messages 17 | include line numbers. No output means that the files given are valid TOML, or 18 | there is a bug in `tomlv`. 19 | 20 | Compatible with TOML version 21 | [v0.4.0](https://github.com/toml-lang/toml/blob/master/versions/en/toml-v0.4.0.md) 22 | -------------------------------------------------------------------------------- /src/github.com/BurntSushi/toml/cmd/tomlv/main.go: -------------------------------------------------------------------------------- 1 | // Command tomlv validates TOML documents and prints each key's type. 2 | package main 3 | 4 | import ( 5 | "flag" 6 | "fmt" 7 | "log" 8 | "os" 9 | "path" 10 | "strings" 11 | "text/tabwriter" 12 | 13 | "github.com/BurntSushi/toml" 14 | ) 15 | 16 | var ( 17 | flagTypes = false 18 | ) 19 | 20 | func init() { 21 | log.SetFlags(0) 22 | 23 | flag.BoolVar(&flagTypes, "types", flagTypes, 24 | "When set, the types of every defined key will be shown.") 25 | 26 | flag.Usage = usage 27 | flag.Parse() 28 | } 29 | 30 | func usage() { 31 | log.Printf("Usage: %s toml-file [ toml-file ... ]\n", 32 | path.Base(os.Args[0])) 33 | flag.PrintDefaults() 34 | 35 | os.Exit(1) 36 | } 37 | 38 | func main() { 39 | if flag.NArg() < 1 { 40 | flag.Usage() 41 | } 42 | for _, f := range flag.Args() { 43 | var tmp interface{} 44 | md, err := toml.DecodeFile(f, &tmp) 45 | if err != nil { 46 | log.Fatalf("Error in '%s': %s", f, err) 47 | } 48 | if flagTypes { 49 | printTypes(md) 50 | } 51 | } 52 | } 53 | 54 | func printTypes(md toml.MetaData) { 55 | tabw := tabwriter.NewWriter(os.Stdout, 0, 0, 2, ' ', 0) 56 | for _, key := range md.Keys() { 57 | fmt.Fprintf(tabw, "%s%s\t%s\n", 58 | strings.Repeat(" ", len(key)-1), key, md.Type(key...)) 59 | } 60 | tabw.Flush() 61 | } 62 | -------------------------------------------------------------------------------- /src/github.com/BurntSushi/toml/decode_meta.go: -------------------------------------------------------------------------------- 1 | package toml 2 | 3 | import "strings" 4 | 5 | // MetaData allows access to meta information about TOML data that may not 6 | // be inferrable via reflection. In particular, whether a key has been defined 7 | // and the TOML type of a key. 8 | type MetaData struct { 9 | mapping map[string]interface{} 10 | types map[string]tomlType 11 | keys []Key 12 | decoded map[string]bool 13 | context Key // Used only during decoding. 14 | } 15 | 16 | // IsDefined returns true if the key given exists in the TOML data. The key 17 | // should be specified hierarchially. e.g., 18 | // 19 | // // access the TOML key 'a.b.c' 20 | // IsDefined("a", "b", "c") 21 | // 22 | // IsDefined will return false if an empty key given. Keys are case sensitive. 23 | func (md *MetaData) IsDefined(key ...string) bool { 24 | if len(key) == 0 { 25 | return false 26 | } 27 | 28 | var hash map[string]interface{} 29 | var ok bool 30 | var hashOrVal interface{} = md.mapping 31 | for _, k := range key { 32 | if hash, ok = hashOrVal.(map[string]interface{}); !ok { 33 | return false 34 | } 35 | if hashOrVal, ok = hash[k]; !ok { 36 | return false 37 | } 38 | } 39 | return true 40 | } 41 | 42 | // Type returns a string representation of the type of the key specified. 43 | // 44 | // Type will return the empty string if given an empty key or a key that 45 | // does not exist. Keys are case sensitive. 46 | func (md *MetaData) Type(key ...string) string { 47 | fullkey := strings.Join(key, ".") 48 | if typ, ok := md.types[fullkey]; ok { 49 | return typ.typeString() 50 | } 51 | return "" 52 | } 53 | 54 | // Key is the type of any TOML key, including key groups. Use (MetaData).Keys 55 | // to get values of this type. 56 | type Key []string 57 | 58 | func (k Key) String() string { 59 | return strings.Join(k, ".") 60 | } 61 | 62 | func (k Key) maybeQuotedAll() string { 63 | var ss []string 64 | for i := range k { 65 | ss = append(ss, k.maybeQuoted(i)) 66 | } 67 | return strings.Join(ss, ".") 68 | } 69 | 70 | func (k Key) maybeQuoted(i int) string { 71 | quote := false 72 | for _, c := range k[i] { 73 | if !isBareKeyChar(c) { 74 | quote = true 75 | break 76 | } 77 | } 78 | if quote { 79 | return "\"" + strings.Replace(k[i], "\"", "\\\"", -1) + "\"" 80 | } 81 | return k[i] 82 | } 83 | 84 | func (k Key) add(piece string) Key { 85 | newKey := make(Key, len(k)+1) 86 | copy(newKey, k) 87 | newKey[len(k)] = piece 88 | return newKey 89 | } 90 | 91 | // Keys returns a slice of every key in the TOML data, including key groups. 92 | // Each key is itself a slice, where the first element is the top of the 93 | // hierarchy and the last is the most specific. 94 | // 95 | // The list will have the same order as the keys appeared in the TOML data. 96 | // 97 | // All keys returned are non-empty. 98 | func (md *MetaData) Keys() []Key { 99 | return md.keys 100 | } 101 | 102 | // Undecoded returns all keys that have not been decoded in the order in which 103 | // they appear in the original TOML document. 104 | // 105 | // This includes keys that haven't been decoded because of a Primitive value. 106 | // Once the Primitive value is decoded, the keys will be considered decoded. 107 | // 108 | // Also note that decoding into an empty interface will result in no decoding, 109 | // and so no keys will be considered decoded. 110 | // 111 | // In this sense, the Undecoded keys correspond to keys in the TOML document 112 | // that do not have a concrete type in your representation. 113 | func (md *MetaData) Undecoded() []Key { 114 | undecoded := make([]Key, 0, len(md.keys)) 115 | for _, key := range md.keys { 116 | if !md.decoded[key.String()] { 117 | undecoded = append(undecoded, key) 118 | } 119 | } 120 | return undecoded 121 | } 122 | -------------------------------------------------------------------------------- /src/github.com/BurntSushi/toml/doc.go: -------------------------------------------------------------------------------- 1 | /* 2 | Package toml provides facilities for decoding and encoding TOML configuration 3 | files via reflection. There is also support for delaying decoding with 4 | the Primitive type, and querying the set of keys in a TOML document with the 5 | MetaData type. 6 | 7 | The specification implemented: https://github.com/toml-lang/toml 8 | 9 | The sub-command github.com/BurntSushi/toml/cmd/tomlv can be used to verify 10 | whether a file is a valid TOML document. It can also be used to print the 11 | type of each key in a TOML document. 12 | 13 | Testing 14 | 15 | There are two important types of tests used for this package. The first is 16 | contained inside '*_test.go' files and uses the standard Go unit testing 17 | framework. These tests are primarily devoted to holistically testing the 18 | decoder and encoder. 19 | 20 | The second type of testing is used to verify the implementation's adherence 21 | to the TOML specification. These tests have been factored into their own 22 | project: https://github.com/BurntSushi/toml-test 23 | 24 | The reason the tests are in a separate project is so that they can be used by 25 | any implementation of TOML. Namely, it is language agnostic. 26 | */ 27 | package toml 28 | -------------------------------------------------------------------------------- /src/github.com/BurntSushi/toml/encoding_types.go: -------------------------------------------------------------------------------- 1 | // +build go1.2 2 | 3 | package toml 4 | 5 | // In order to support Go 1.1, we define our own TextMarshaler and 6 | // TextUnmarshaler types. For Go 1.2+, we just alias them with the 7 | // standard library interfaces. 8 | 9 | import ( 10 | "encoding" 11 | ) 12 | 13 | // TextMarshaler is a synonym for encoding.TextMarshaler. It is defined here 14 | // so that Go 1.1 can be supported. 15 | type TextMarshaler encoding.TextMarshaler 16 | 17 | // TextUnmarshaler is a synonym for encoding.TextUnmarshaler. It is defined 18 | // here so that Go 1.1 can be supported. 19 | type TextUnmarshaler encoding.TextUnmarshaler 20 | -------------------------------------------------------------------------------- /src/github.com/BurntSushi/toml/encoding_types_1.1.go: -------------------------------------------------------------------------------- 1 | // +build !go1.2 2 | 3 | package toml 4 | 5 | // These interfaces were introduced in Go 1.2, so we add them manually when 6 | // compiling for Go 1.1. 7 | 8 | // TextMarshaler is a synonym for encoding.TextMarshaler. It is defined here 9 | // so that Go 1.1 can be supported. 10 | type TextMarshaler interface { 11 | MarshalText() (text []byte, err error) 12 | } 13 | 14 | // TextUnmarshaler is a synonym for encoding.TextUnmarshaler. It is defined 15 | // here so that Go 1.1 can be supported. 16 | type TextUnmarshaler interface { 17 | UnmarshalText(text []byte) error 18 | } 19 | -------------------------------------------------------------------------------- /src/github.com/BurntSushi/toml/session.vim: -------------------------------------------------------------------------------- 1 | au BufWritePost *.go silent!make tags > /dev/null 2>&1 2 | -------------------------------------------------------------------------------- /src/github.com/BurntSushi/toml/type_check.go: -------------------------------------------------------------------------------- 1 | package toml 2 | 3 | // tomlType represents any Go type that corresponds to a TOML type. 4 | // While the first draft of the TOML spec has a simplistic type system that 5 | // probably doesn't need this level of sophistication, we seem to be militating 6 | // toward adding real composite types. 7 | type tomlType interface { 8 | typeString() string 9 | } 10 | 11 | // typeEqual accepts any two types and returns true if they are equal. 12 | func typeEqual(t1, t2 tomlType) bool { 13 | if t1 == nil || t2 == nil { 14 | return false 15 | } 16 | return t1.typeString() == t2.typeString() 17 | } 18 | 19 | func typeIsHash(t tomlType) bool { 20 | return typeEqual(t, tomlHash) || typeEqual(t, tomlArrayHash) 21 | } 22 | 23 | type tomlBaseType string 24 | 25 | func (btype tomlBaseType) typeString() string { 26 | return string(btype) 27 | } 28 | 29 | func (btype tomlBaseType) String() string { 30 | return btype.typeString() 31 | } 32 | 33 | var ( 34 | tomlInteger tomlBaseType = "Integer" 35 | tomlFloat tomlBaseType = "Float" 36 | tomlDatetime tomlBaseType = "Datetime" 37 | tomlString tomlBaseType = "String" 38 | tomlBool tomlBaseType = "Bool" 39 | tomlArray tomlBaseType = "Array" 40 | tomlHash tomlBaseType = "Hash" 41 | tomlArrayHash tomlBaseType = "ArrayHash" 42 | ) 43 | 44 | // typeOfPrimitive returns a tomlType of any primitive value in TOML. 45 | // Primitive values are: Integer, Float, Datetime, String and Bool. 46 | // 47 | // Passing a lexer item other than the following will cause a BUG message 48 | // to occur: itemString, itemBool, itemInteger, itemFloat, itemDatetime. 49 | func (p *parser) typeOfPrimitive(lexItem item) tomlType { 50 | switch lexItem.typ { 51 | case itemInteger: 52 | return tomlInteger 53 | case itemFloat: 54 | return tomlFloat 55 | case itemDatetime: 56 | return tomlDatetime 57 | case itemString: 58 | return tomlString 59 | case itemMultilineString: 60 | return tomlString 61 | case itemRawString: 62 | return tomlString 63 | case itemRawMultilineString: 64 | return tomlString 65 | case itemBool: 66 | return tomlBool 67 | } 68 | p.bug("Cannot infer primitive type of lex item '%s'.", lexItem) 69 | panic("unreachable") 70 | } 71 | 72 | // typeOfArray returns a tomlType for an array given a list of types of its 73 | // values. 74 | // 75 | // In the current spec, if an array is homogeneous, then its type is always 76 | // "Array". If the array is not homogeneous, an error is generated. 77 | func (p *parser) typeOfArray(types []tomlType) tomlType { 78 | // Empty arrays are cool. 79 | if len(types) == 0 { 80 | return tomlArray 81 | } 82 | 83 | theType := types[0] 84 | for _, t := range types[1:] { 85 | if !typeEqual(theType, t) { 86 | p.panicf("Array contains values of type '%s' and '%s', but "+ 87 | "arrays must be homogeneous.", theType, t) 88 | } 89 | } 90 | return tomlArray 91 | } 92 | -------------------------------------------------------------------------------- /src/github.com/BurntSushi/toml/type_fields.go: -------------------------------------------------------------------------------- 1 | package toml 2 | 3 | // Struct field handling is adapted from code in encoding/json: 4 | // 5 | // Copyright 2010 The Go Authors. All rights reserved. 6 | // Use of this source code is governed by a BSD-style 7 | // license that can be found in the Go distribution. 8 | 9 | import ( 10 | "reflect" 11 | "sort" 12 | "sync" 13 | ) 14 | 15 | // A field represents a single field found in a struct. 16 | type field struct { 17 | name string // the name of the field (`toml` tag included) 18 | tag bool // whether field has a `toml` tag 19 | index []int // represents the depth of an anonymous field 20 | typ reflect.Type // the type of the field 21 | } 22 | 23 | // byName sorts field by name, breaking ties with depth, 24 | // then breaking ties with "name came from toml tag", then 25 | // breaking ties with index sequence. 26 | type byName []field 27 | 28 | func (x byName) Len() int { return len(x) } 29 | 30 | func (x byName) Swap(i, j int) { x[i], x[j] = x[j], x[i] } 31 | 32 | func (x byName) Less(i, j int) bool { 33 | if x[i].name != x[j].name { 34 | return x[i].name < x[j].name 35 | } 36 | if len(x[i].index) != len(x[j].index) { 37 | return len(x[i].index) < len(x[j].index) 38 | } 39 | if x[i].tag != x[j].tag { 40 | return x[i].tag 41 | } 42 | return byIndex(x).Less(i, j) 43 | } 44 | 45 | // byIndex sorts field by index sequence. 46 | type byIndex []field 47 | 48 | func (x byIndex) Len() int { return len(x) } 49 | 50 | func (x byIndex) Swap(i, j int) { x[i], x[j] = x[j], x[i] } 51 | 52 | func (x byIndex) Less(i, j int) bool { 53 | for k, xik := range x[i].index { 54 | if k >= len(x[j].index) { 55 | return false 56 | } 57 | if xik != x[j].index[k] { 58 | return xik < x[j].index[k] 59 | } 60 | } 61 | return len(x[i].index) < len(x[j].index) 62 | } 63 | 64 | // typeFields returns a list of fields that TOML should recognize for the given 65 | // type. The algorithm is breadth-first search over the set of structs to 66 | // include - the top struct and then any reachable anonymous structs. 67 | func typeFields(t reflect.Type) []field { 68 | // Anonymous fields to explore at the current level and the next. 69 | current := []field{} 70 | next := []field{{typ: t}} 71 | 72 | // Count of queued names for current level and the next. 73 | count := map[reflect.Type]int{} 74 | nextCount := map[reflect.Type]int{} 75 | 76 | // Types already visited at an earlier level. 77 | visited := map[reflect.Type]bool{} 78 | 79 | // Fields found. 80 | var fields []field 81 | 82 | for len(next) > 0 { 83 | current, next = next, current[:0] 84 | count, nextCount = nextCount, map[reflect.Type]int{} 85 | 86 | for _, f := range current { 87 | if visited[f.typ] { 88 | continue 89 | } 90 | visited[f.typ] = true 91 | 92 | // Scan f.typ for fields to include. 93 | for i := 0; i < f.typ.NumField(); i++ { 94 | sf := f.typ.Field(i) 95 | if sf.PkgPath != "" && !sf.Anonymous { // unexported 96 | continue 97 | } 98 | opts := getOptions(sf.Tag) 99 | if opts.skip { 100 | continue 101 | } 102 | index := make([]int, len(f.index)+1) 103 | copy(index, f.index) 104 | index[len(f.index)] = i 105 | 106 | ft := sf.Type 107 | if ft.Name() == "" && ft.Kind() == reflect.Ptr { 108 | // Follow pointer. 109 | ft = ft.Elem() 110 | } 111 | 112 | // Record found field and index sequence. 113 | if opts.name != "" || !sf.Anonymous || ft.Kind() != reflect.Struct { 114 | tagged := opts.name != "" 115 | name := opts.name 116 | if name == "" { 117 | name = sf.Name 118 | } 119 | fields = append(fields, field{name, tagged, index, ft}) 120 | if count[f.typ] > 1 { 121 | // If there were multiple instances, add a second, 122 | // so that the annihilation code will see a duplicate. 123 | // It only cares about the distinction between 1 or 2, 124 | // so don't bother generating any more copies. 125 | fields = append(fields, fields[len(fields)-1]) 126 | } 127 | continue 128 | } 129 | 130 | // Record new anonymous struct to explore in next round. 131 | nextCount[ft]++ 132 | if nextCount[ft] == 1 { 133 | f := field{name: ft.Name(), index: index, typ: ft} 134 | next = append(next, f) 135 | } 136 | } 137 | } 138 | } 139 | 140 | sort.Sort(byName(fields)) 141 | 142 | // Delete all fields that are hidden by the Go rules for embedded fields, 143 | // except that fields with TOML tags are promoted. 144 | 145 | // The fields are sorted in primary order of name, secondary order 146 | // of field index length. Loop over names; for each name, delete 147 | // hidden fields by choosing the one dominant field that survives. 148 | out := fields[:0] 149 | for advance, i := 0, 0; i < len(fields); i += advance { 150 | // One iteration per name. 151 | // Find the sequence of fields with the name of this first field. 152 | fi := fields[i] 153 | name := fi.name 154 | for advance = 1; i+advance < len(fields); advance++ { 155 | fj := fields[i+advance] 156 | if fj.name != name { 157 | break 158 | } 159 | } 160 | if advance == 1 { // Only one field with this name 161 | out = append(out, fi) 162 | continue 163 | } 164 | dominant, ok := dominantField(fields[i : i+advance]) 165 | if ok { 166 | out = append(out, dominant) 167 | } 168 | } 169 | 170 | fields = out 171 | sort.Sort(byIndex(fields)) 172 | 173 | return fields 174 | } 175 | 176 | // dominantField looks through the fields, all of which are known to 177 | // have the same name, to find the single field that dominates the 178 | // others using Go's embedding rules, modified by the presence of 179 | // TOML tags. If there are multiple top-level fields, the boolean 180 | // will be false: This condition is an error in Go and we skip all 181 | // the fields. 182 | func dominantField(fields []field) (field, bool) { 183 | // The fields are sorted in increasing index-length order. The winner 184 | // must therefore be one with the shortest index length. Drop all 185 | // longer entries, which is easy: just truncate the slice. 186 | length := len(fields[0].index) 187 | tagged := -1 // Index of first tagged field. 188 | for i, f := range fields { 189 | if len(f.index) > length { 190 | fields = fields[:i] 191 | break 192 | } 193 | if f.tag { 194 | if tagged >= 0 { 195 | // Multiple tagged fields at the same level: conflict. 196 | // Return no field. 197 | return field{}, false 198 | } 199 | tagged = i 200 | } 201 | } 202 | if tagged >= 0 { 203 | return fields[tagged], true 204 | } 205 | // All remaining fields have the same length. If there's more than one, 206 | // we have a conflict (two fields named "X" at the same level) and we 207 | // return no field. 208 | if len(fields) > 1 { 209 | return field{}, false 210 | } 211 | return fields[0], true 212 | } 213 | 214 | var fieldCache struct { 215 | sync.RWMutex 216 | m map[reflect.Type][]field 217 | } 218 | 219 | // cachedTypeFields is like typeFields but uses a cache to avoid repeated work. 220 | func cachedTypeFields(t reflect.Type) []field { 221 | fieldCache.RLock() 222 | f := fieldCache.m[t] 223 | fieldCache.RUnlock() 224 | if f != nil { 225 | return f 226 | } 227 | 228 | // Compute fields without lock. 229 | // Might duplicate effort but won't hold other computations back. 230 | f = typeFields(t) 231 | if f == nil { 232 | f = []field{} 233 | } 234 | 235 | fieldCache.Lock() 236 | if fieldCache.m == nil { 237 | fieldCache.m = map[reflect.Type][]field{} 238 | } 239 | fieldCache.m[t] = f 240 | fieldCache.Unlock() 241 | return f 242 | } 243 | -------------------------------------------------------------------------------- /src/github.com/atotto/clipboard/LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2013 Ato Araki. All rights reserved. 2 | 3 | Redistribution and use in source and binary forms, with or without 4 | modification, are permitted provided that the following conditions are 5 | met: 6 | 7 | * Redistributions of source code must retain the above copyright 8 | notice, this list of conditions and the following disclaimer. 9 | * Redistributions in binary form must reproduce the above 10 | copyright notice, this list of conditions and the following disclaimer 11 | in the documentation and/or other materials provided with the 12 | distribution. 13 | * Neither the name of @atotto. nor the names of its 14 | contributors may be used to endorse or promote products derived from 15 | this software without specific prior written permission. 16 | 17 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 18 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 19 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 20 | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 21 | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 22 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 23 | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 24 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 25 | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 26 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 27 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 | -------------------------------------------------------------------------------- /src/github.com/atotto/clipboard/README.md: -------------------------------------------------------------------------------- 1 | [![Build Status](https://travis-ci.org/atotto/clipboard.svg?branch=master)](https://travis-ci.org/atotto/clipboard) [![Build Status](https://drone.io/github.com/atotto/clipboard/status.png)](https://drone.io/github.com/atotto/clipboard/latest) 2 | 3 | [![GoDoc](https://godoc.org/github.com/atotto/clipboard?status.svg)](http://godoc.org/github.com/atotto/clipboard) 4 | 5 | # Clipboard for Go 6 | 7 | Provide copying and pasting to the Clipboard for Go. 8 | 9 | Download shell commands at https://drone.io/github.com/atotto/clipboard/files 10 | 11 | Build: 12 | 13 | $ go get github.com/atotto/clipboard 14 | 15 | Platforms: 16 | 17 | * OSX 18 | * Windows 7 (probably work on other Windows) 19 | * Linux, Unix (requires 'xclip' or 'xsel' command to be installed) 20 | 21 | 22 | Document: 23 | 24 | * http://godoc.org/github.com/atotto/clipboard 25 | 26 | Notes: 27 | 28 | * Text string only 29 | * UTF-8 text encoding only (no conversion) 30 | 31 | TODO: 32 | 33 | * Clipboard watcher(?) 34 | 35 | ## Commands: 36 | 37 | paste shell command: 38 | 39 | $ go get github.com/atotto/clipboard/cmd/gopaste 40 | $ # example: 41 | $ gopaste > document.txt 42 | 43 | copy shell command: 44 | 45 | $ go get github.com/atotto/clipboard/cmd/gocopy 46 | $ # example: 47 | $ cat document.txt | gocopy 48 | 49 | 50 | 51 | -------------------------------------------------------------------------------- /src/github.com/atotto/clipboard/clipboard.go: -------------------------------------------------------------------------------- 1 | // Copyright 2013 @atotto. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | // Package clipboard read/write on clipboard 6 | package clipboard 7 | 8 | import () 9 | 10 | // ReadAll read string from clipboard 11 | func ReadAll() (string, error) { 12 | return readAll() 13 | } 14 | 15 | // WriteAll write string to clipboard 16 | func WriteAll(text string) error { 17 | return writeAll(text) 18 | } 19 | 20 | // Unsupported might be set true during clipboard init, to help callers decide 21 | // whether or not to offer clipboard options. 22 | var Unsupported bool 23 | -------------------------------------------------------------------------------- /src/github.com/atotto/clipboard/clipboard_darwin.go: -------------------------------------------------------------------------------- 1 | // Copyright 2013 @atotto. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | // +build darwin 6 | 7 | package clipboard 8 | 9 | import ( 10 | "os/exec" 11 | ) 12 | 13 | var ( 14 | pasteCmdArgs = "pbpaste" 15 | copyCmdArgs = "pbcopy" 16 | ) 17 | 18 | func getPasteCommand() *exec.Cmd { 19 | return exec.Command(pasteCmdArgs) 20 | } 21 | 22 | func getCopyCommand() *exec.Cmd { 23 | return exec.Command(copyCmdArgs) 24 | } 25 | 26 | func readAll() (string, error) { 27 | pasteCmd := getPasteCommand() 28 | out, err := pasteCmd.Output() 29 | if err != nil { 30 | return "", err 31 | } 32 | return string(out), nil 33 | } 34 | 35 | func writeAll(text string) error { 36 | copyCmd := getCopyCommand() 37 | in, err := copyCmd.StdinPipe() 38 | if err != nil { 39 | return err 40 | } 41 | 42 | if err := copyCmd.Start(); err != nil { 43 | return err 44 | } 45 | if _, err := in.Write([]byte(text)); err != nil { 46 | return err 47 | } 48 | if err := in.Close(); err != nil { 49 | return err 50 | } 51 | return copyCmd.Wait() 52 | } 53 | -------------------------------------------------------------------------------- /src/github.com/atotto/clipboard/clipboard_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2013 @atotto. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | package clipboard_test 6 | 7 | import ( 8 | "testing" 9 | 10 | . "github.com/atotto/clipboard" 11 | ) 12 | 13 | func TestCopyAndPaste(t *testing.T) { 14 | expected := "日本語" 15 | 16 | err := WriteAll(expected) 17 | if err != nil { 18 | t.Fatal(err) 19 | } 20 | 21 | actual, err := ReadAll() 22 | if err != nil { 23 | t.Fatal(err) 24 | } 25 | 26 | if actual != expected { 27 | t.Errorf("want %s, got %s", expected, actual) 28 | } 29 | } 30 | 31 | func TestMultiCopyAndPaste(t *testing.T) { 32 | expected1 := "French: éèêëàùœç" 33 | expected2 := "Weird UTF-8: 💩☃" 34 | 35 | err := WriteAll(expected1) 36 | if err != nil { 37 | t.Fatal(err) 38 | } 39 | 40 | actual1, err := ReadAll() 41 | if err != nil { 42 | t.Fatal(err) 43 | } 44 | if actual1 != expected1 { 45 | t.Errorf("want %s, got %s", expected1, actual1) 46 | } 47 | 48 | err = WriteAll(expected2) 49 | if err != nil { 50 | t.Fatal(err) 51 | } 52 | 53 | actual2, err := ReadAll() 54 | if err != nil { 55 | t.Fatal(err) 56 | } 57 | if actual2 != expected2 { 58 | t.Errorf("want %s, got %s", expected2, actual2) 59 | } 60 | } 61 | 62 | func BenchmarkReadAll(b *testing.B) { 63 | for i := 0; i < b.N; i++ { 64 | ReadAll() 65 | } 66 | } 67 | 68 | func BenchmarkWriteAll(b *testing.B) { 69 | text := "いろはにほへと" 70 | for i := 0; i < b.N; i++ { 71 | WriteAll(text) 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /src/github.com/atotto/clipboard/clipboard_unix.go: -------------------------------------------------------------------------------- 1 | // Copyright 2013 @atotto. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | // +build freebsd linux netbsd openbsd solaris 6 | 7 | package clipboard 8 | 9 | import ( 10 | "errors" 11 | "os/exec" 12 | ) 13 | 14 | const ( 15 | xsel = "xsel" 16 | xclip = "xclip" 17 | ) 18 | 19 | var ( 20 | pasteCmdArgs []string 21 | copyCmdArgs []string 22 | 23 | xselPasteArgs = []string{xsel, "--output", "--clipboard"} 24 | xselCopyArgs = []string{xsel, "--input", "--clipboard"} 25 | 26 | xclipPasteArgs = []string{xclip, "-out", "-selection", "clipboard"} 27 | xclipCopyArgs = []string{xclip, "-in", "-selection", "clipboard"} 28 | 29 | missingCommands = errors.New("No clipboard utilities available. Please install xsel or xclip.") 30 | ) 31 | 32 | func init() { 33 | pasteCmdArgs = xclipPasteArgs 34 | copyCmdArgs = xclipCopyArgs 35 | 36 | if _, err := exec.LookPath(xclip); err == nil { 37 | return 38 | } 39 | 40 | pasteCmdArgs = xselPasteArgs 41 | copyCmdArgs = xselCopyArgs 42 | 43 | if _, err := exec.LookPath(xsel); err == nil { 44 | return 45 | } 46 | 47 | Unsupported = true 48 | } 49 | 50 | func getPasteCommand() *exec.Cmd { 51 | return exec.Command(pasteCmdArgs[0], pasteCmdArgs[1:]...) 52 | } 53 | 54 | func getCopyCommand() *exec.Cmd { 55 | return exec.Command(copyCmdArgs[0], copyCmdArgs[1:]...) 56 | } 57 | 58 | func readAll() (string, error) { 59 | if Unsupported { 60 | return "", missingCommands 61 | } 62 | pasteCmd := getPasteCommand() 63 | out, err := pasteCmd.Output() 64 | if err != nil { 65 | return "", err 66 | } 67 | return string(out), nil 68 | } 69 | 70 | func writeAll(text string) error { 71 | if Unsupported { 72 | return missingCommands 73 | } 74 | copyCmd := getCopyCommand() 75 | in, err := copyCmd.StdinPipe() 76 | if err != nil { 77 | return err 78 | } 79 | 80 | if err := copyCmd.Start(); err != nil { 81 | return err 82 | } 83 | if _, err := in.Write([]byte(text)); err != nil { 84 | return err 85 | } 86 | if err := in.Close(); err != nil { 87 | return err 88 | } 89 | return copyCmd.Wait() 90 | } 91 | -------------------------------------------------------------------------------- /src/github.com/atotto/clipboard/clipboard_windows.go: -------------------------------------------------------------------------------- 1 | // Copyright 2013 @atotto. All rights reserved. 2 | // Use of this source code is governed by a BSD-style 3 | // license that can be found in the LICENSE file. 4 | 5 | // +build windows 6 | 7 | package clipboard 8 | 9 | import ( 10 | "syscall" 11 | "unsafe" 12 | ) 13 | 14 | const ( 15 | cfUnicodetext = 13 16 | gmemFixed = 0x0000 17 | ) 18 | 19 | var ( 20 | user32 = syscall.MustLoadDLL("user32") 21 | openClipboard = user32.MustFindProc("OpenClipboard") 22 | closeClipboard = user32.MustFindProc("CloseClipboard") 23 | emptyClipboard = user32.MustFindProc("EmptyClipboard") 24 | getClipboardData = user32.MustFindProc("GetClipboardData") 25 | setClipboardData = user32.MustFindProc("SetClipboardData") 26 | 27 | kernel32 = syscall.NewLazyDLL("kernel32") 28 | globalAlloc = kernel32.NewProc("GlobalAlloc") 29 | globalFree = kernel32.NewProc("GlobalFree") 30 | globalLock = kernel32.NewProc("GlobalLock") 31 | globalUnlock = kernel32.NewProc("GlobalUnlock") 32 | lstrcpy = kernel32.NewProc("lstrcpyW") 33 | ) 34 | 35 | func readAll() (string, error) { 36 | r, _, err := openClipboard.Call(0) 37 | if r == 0 { 38 | return "", err 39 | } 40 | defer closeClipboard.Call() 41 | 42 | h, _, err := getClipboardData.Call(cfUnicodetext) 43 | if r == 0 { 44 | return "", err 45 | } 46 | 47 | l, _, err := globalLock.Call(h) 48 | if l == 0 { 49 | return "", err 50 | } 51 | 52 | text := syscall.UTF16ToString((*[1 << 20]uint16)(unsafe.Pointer(l))[:]) 53 | 54 | r, _, err = globalUnlock.Call(h) 55 | if r == 0 { 56 | return "", err 57 | } 58 | 59 | return text, nil 60 | } 61 | 62 | func writeAll(text string) error { 63 | r, _, err := openClipboard.Call(0) 64 | if r == 0 { 65 | return err 66 | } 67 | defer closeClipboard.Call() 68 | 69 | r, _, err = emptyClipboard.Call(0) 70 | if r == 0 { 71 | return err 72 | } 73 | 74 | data := syscall.StringToUTF16(text) 75 | 76 | h, _, err := globalAlloc.Call(gmemFixed, uintptr(len(data)*int(unsafe.Sizeof(data[0])))) 77 | if h == 0 { 78 | return err 79 | } 80 | 81 | l, _, err := globalLock.Call(h) 82 | if l == 0 { 83 | return err 84 | } 85 | 86 | r, _, err = lstrcpy.Call(l, uintptr(unsafe.Pointer(&data[0]))) 87 | if r == 0 { 88 | return err 89 | } 90 | 91 | r, _, err = globalUnlock.Call(h) 92 | if r == 0 { 93 | return err 94 | } 95 | 96 | r, _, err = setClipboardData.Call(cfUnicodetext, h) 97 | if r == 0 { 98 | return err 99 | } 100 | return nil 101 | } 102 | -------------------------------------------------------------------------------- /src/github.com/atotto/clipboard/cmd/gocopy/gocopy.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "io/ioutil" 5 | "os" 6 | 7 | "github.com/atotto/clipboard" 8 | ) 9 | 10 | func main() { 11 | 12 | out, err := ioutil.ReadAll(os.Stdin) 13 | if err != nil { 14 | panic(err) 15 | } 16 | 17 | if err := clipboard.WriteAll(string(out)); err != nil { 18 | panic(err) 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/github.com/atotto/clipboard/cmd/gopaste/gopaste.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | 6 | "github.com/atotto/clipboard" 7 | ) 8 | 9 | func main() { 10 | text, err := clipboard.ReadAll() 11 | if err != nil { 12 | panic(err) 13 | } 14 | 15 | fmt.Print(text) 16 | } 17 | -------------------------------------------------------------------------------- /src/github.com/atotto/clipboard/example_test.go: -------------------------------------------------------------------------------- 1 | package clipboard_test 2 | 3 | import ( 4 | "fmt" 5 | 6 | "github.com/atotto/clipboard" 7 | ) 8 | 9 | func Example() { 10 | clipboard.WriteAll("日本語") 11 | text, _ := clipboard.ReadAll() 12 | fmt.Println(text) 13 | 14 | // Output: 15 | // 日本語 16 | } 17 | -------------------------------------------------------------------------------- /src/github.com/mitchellh/go-homedir/LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2013 Mitchell Hashimoto 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 13 | all 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 21 | THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /src/github.com/mitchellh/go-homedir/README.md: -------------------------------------------------------------------------------- 1 | # go-homedir 2 | 3 | This is a Go library for detecting the user's home directory without 4 | the use of cgo, so the library can be used in cross-compilation environments. 5 | 6 | Usage is incredibly simple, just call `homedir.Dir()` to get the home directory 7 | for a user, and `homedir.Expand()` to expand the `~` in a path to the home 8 | directory. 9 | 10 | **Why not just use `os/user`?** The built-in `os/user` package requires 11 | cgo on Darwin systems. This means that any Go code that uses that package 12 | cannot cross compile. But 99% of the time the use for `os/user` is just to 13 | retrieve the home directory, which we can do for the current user without 14 | cgo. This library does that, enabling cross-compilation. 15 | -------------------------------------------------------------------------------- /src/github.com/mitchellh/go-homedir/homedir.go: -------------------------------------------------------------------------------- 1 | package homedir 2 | 3 | import ( 4 | "bytes" 5 | "errors" 6 | "os" 7 | "os/exec" 8 | "path/filepath" 9 | "runtime" 10 | "strconv" 11 | "strings" 12 | "sync" 13 | ) 14 | 15 | // DisableCache will disable caching of the home directory. Caching is enabled 16 | // by default. 17 | var DisableCache bool 18 | 19 | var homedirCache string 20 | var cacheLock sync.RWMutex 21 | 22 | // Dir returns the home directory for the executing user. 23 | // 24 | // This uses an OS-specific method for discovering the home directory. 25 | // An error is returned if a home directory cannot be detected. 26 | func Dir() (string, error) { 27 | if !DisableCache { 28 | cacheLock.RLock() 29 | cached := homedirCache 30 | cacheLock.RUnlock() 31 | if cached != "" { 32 | return cached, nil 33 | } 34 | } 35 | 36 | cacheLock.Lock() 37 | defer cacheLock.Unlock() 38 | 39 | var result string 40 | var err error 41 | if runtime.GOOS == "windows" { 42 | result, err = dirWindows() 43 | } else { 44 | // Unix-like system, so just assume Unix 45 | result, err = dirUnix() 46 | } 47 | 48 | if err != nil { 49 | return "", err 50 | } 51 | homedirCache = result 52 | return result, nil 53 | } 54 | 55 | // Expand expands the path to include the home directory if the path 56 | // is prefixed with `~`. If it isn't prefixed with `~`, the path is 57 | // returned as-is. 58 | func Expand(path string) (string, error) { 59 | if len(path) == 0 { 60 | return path, nil 61 | } 62 | 63 | if path[0] != '~' { 64 | return path, nil 65 | } 66 | 67 | if len(path) > 1 && path[1] != '/' && path[1] != '\\' { 68 | return "", errors.New("cannot expand user-specific home dir") 69 | } 70 | 71 | dir, err := Dir() 72 | if err != nil { 73 | return "", err 74 | } 75 | 76 | return filepath.Join(dir, path[1:]), nil 77 | } 78 | 79 | func dirUnix() (string, error) { 80 | // First prefer the HOME environmental variable 81 | if home := os.Getenv("HOME"); home != "" { 82 | return home, nil 83 | } 84 | 85 | // If that fails, try getent 86 | var stdout bytes.Buffer 87 | cmd := exec.Command("getent", "passwd", strconv.Itoa(os.Getuid())) 88 | cmd.Stdout = &stdout 89 | if err := cmd.Run(); err != nil { 90 | // If the error is ErrNotFound, we ignore it. Otherwise, return it. 91 | if err != exec.ErrNotFound { 92 | return "", err 93 | } 94 | } else { 95 | if passwd := strings.TrimSpace(stdout.String()); passwd != "" { 96 | // username:password:uid:gid:gecos:home:shell 97 | passwdParts := strings.SplitN(passwd, ":", 7) 98 | if len(passwdParts) > 5 { 99 | return passwdParts[5], nil 100 | } 101 | } 102 | } 103 | 104 | // If all else fails, try the shell 105 | stdout.Reset() 106 | cmd = exec.Command("sh", "-c", "cd && pwd") 107 | cmd.Stdout = &stdout 108 | if err := cmd.Run(); err != nil { 109 | return "", err 110 | } 111 | 112 | result := strings.TrimSpace(stdout.String()) 113 | if result == "" { 114 | return "", errors.New("blank output when reading home directory") 115 | } 116 | 117 | return result, nil 118 | } 119 | 120 | func dirWindows() (string, error) { 121 | // First prefer the HOME environmental variable 122 | if home := os.Getenv("HOME"); home != "" { 123 | return home, nil 124 | } 125 | 126 | drive := os.Getenv("HOMEDRIVE") 127 | path := os.Getenv("HOMEPATH") 128 | home := drive + path 129 | if drive == "" || path == "" { 130 | home = os.Getenv("USERPROFILE") 131 | } 132 | if home == "" { 133 | return "", errors.New("HOMEDRIVE, HOMEPATH, and USERPROFILE are blank") 134 | } 135 | 136 | return home, nil 137 | } 138 | -------------------------------------------------------------------------------- /src/github.com/mitchellh/go-homedir/homedir_test.go: -------------------------------------------------------------------------------- 1 | package homedir 2 | 3 | import ( 4 | "os" 5 | "os/user" 6 | "path/filepath" 7 | "testing" 8 | ) 9 | 10 | func patchEnv(key, value string) func() { 11 | bck := os.Getenv(key) 12 | deferFunc := func() { 13 | os.Setenv(key, bck) 14 | } 15 | 16 | os.Setenv(key, value) 17 | return deferFunc 18 | } 19 | 20 | func BenchmarkDir(b *testing.B) { 21 | // We do this for any "warmups" 22 | for i := 0; i < 10; i++ { 23 | Dir() 24 | } 25 | 26 | b.ResetTimer() 27 | for i := 0; i < b.N; i++ { 28 | Dir() 29 | } 30 | } 31 | 32 | func TestDir(t *testing.T) { 33 | u, err := user.Current() 34 | if err != nil { 35 | t.Fatalf("err: %s", err) 36 | } 37 | 38 | dir, err := Dir() 39 | if err != nil { 40 | t.Fatalf("err: %s", err) 41 | } 42 | 43 | if u.HomeDir != dir { 44 | t.Fatalf("%#v != %#v", u.HomeDir, dir) 45 | } 46 | } 47 | 48 | func TestExpand(t *testing.T) { 49 | u, err := user.Current() 50 | if err != nil { 51 | t.Fatalf("err: %s", err) 52 | } 53 | 54 | cases := []struct { 55 | Input string 56 | Output string 57 | Err bool 58 | }{ 59 | { 60 | "/foo", 61 | "/foo", 62 | false, 63 | }, 64 | 65 | { 66 | "~/foo", 67 | filepath.Join(u.HomeDir, "foo"), 68 | false, 69 | }, 70 | 71 | { 72 | "", 73 | "", 74 | false, 75 | }, 76 | 77 | { 78 | "~", 79 | u.HomeDir, 80 | false, 81 | }, 82 | 83 | { 84 | "~foo/foo", 85 | "", 86 | true, 87 | }, 88 | } 89 | 90 | for _, tc := range cases { 91 | actual, err := Expand(tc.Input) 92 | if (err != nil) != tc.Err { 93 | t.Fatalf("Input: %#v\n\nErr: %s", tc.Input, err) 94 | } 95 | 96 | if actual != tc.Output { 97 | t.Fatalf("Input: %#v\n\nOutput: %#v", tc.Input, actual) 98 | } 99 | } 100 | 101 | DisableCache = true 102 | defer func() { DisableCache = false }() 103 | defer patchEnv("HOME", "/custom/path/")() 104 | expected := filepath.Join("/", "custom", "path", "foo/bar") 105 | actual, err := Expand("~/foo/bar") 106 | 107 | if err != nil { 108 | t.Errorf("No error is expected, got: %v", err) 109 | } else if actual != expected { 110 | t.Errorf("Expected: %v; actual: %v", expected, actual) 111 | } 112 | } 113 | -------------------------------------------------------------------------------- /src/gopkg.in/urfave/cli.v1/LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2016 Jeremy Saenz & Contributors 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 | -------------------------------------------------------------------------------- /src/gopkg.in/urfave/cli.v1/altsrc/altsrc.go: -------------------------------------------------------------------------------- 1 | package altsrc 2 | 3 | //go:generate python ../generate-flag-types altsrc -i ../flag-types.json -o flag_generated.go 4 | -------------------------------------------------------------------------------- /src/gopkg.in/urfave/cli.v1/altsrc/flag.go: -------------------------------------------------------------------------------- 1 | package altsrc 2 | 3 | import ( 4 | "fmt" 5 | "strconv" 6 | "strings" 7 | "syscall" 8 | 9 | "gopkg.in/urfave/cli.v1" 10 | ) 11 | 12 | // FlagInputSourceExtension is an extension interface of cli.Flag that 13 | // allows a value to be set on the existing parsed flags. 14 | type FlagInputSourceExtension interface { 15 | cli.Flag 16 | ApplyInputSourceValue(context *cli.Context, isc InputSourceContext) error 17 | } 18 | 19 | // ApplyInputSourceValues iterates over all provided flags and 20 | // executes ApplyInputSourceValue on flags implementing the 21 | // FlagInputSourceExtension interface to initialize these flags 22 | // to an alternate input source. 23 | func ApplyInputSourceValues(context *cli.Context, inputSourceContext InputSourceContext, flags []cli.Flag) error { 24 | for _, f := range flags { 25 | inputSourceExtendedFlag, isType := f.(FlagInputSourceExtension) 26 | if isType { 27 | err := inputSourceExtendedFlag.ApplyInputSourceValue(context, inputSourceContext) 28 | if err != nil { 29 | return err 30 | } 31 | } 32 | } 33 | 34 | return nil 35 | } 36 | 37 | // InitInputSource is used to to setup an InputSourceContext on a cli.Command Before method. It will create a new 38 | // input source based on the func provided. If there is no error it will then apply the new input source to any flags 39 | // that are supported by the input source 40 | func InitInputSource(flags []cli.Flag, createInputSource func() (InputSourceContext, error)) cli.BeforeFunc { 41 | return func(context *cli.Context) error { 42 | inputSource, err := createInputSource() 43 | if err != nil { 44 | return fmt.Errorf("Unable to create input source: inner error: \n'%v'", err.Error()) 45 | } 46 | 47 | return ApplyInputSourceValues(context, inputSource, flags) 48 | } 49 | } 50 | 51 | // InitInputSourceWithContext is used to to setup an InputSourceContext on a cli.Command Before method. It will create a new 52 | // input source based on the func provided with potentially using existing cli.Context values to initialize itself. If there is 53 | // no error it will then apply the new input source to any flags that are supported by the input source 54 | func InitInputSourceWithContext(flags []cli.Flag, createInputSource func(context *cli.Context) (InputSourceContext, error)) cli.BeforeFunc { 55 | return func(context *cli.Context) error { 56 | inputSource, err := createInputSource(context) 57 | if err != nil { 58 | return fmt.Errorf("Unable to create input source with context: inner error: \n'%v'", err.Error()) 59 | } 60 | 61 | return ApplyInputSourceValues(context, inputSource, flags) 62 | } 63 | } 64 | 65 | // ApplyInputSourceValue applies a generic value to the flagSet if required 66 | func (f *GenericFlag) ApplyInputSourceValue(context *cli.Context, isc InputSourceContext) error { 67 | if f.set != nil { 68 | if !context.IsSet(f.Name) && !isEnvVarSet(f.EnvVar) { 69 | value, err := isc.Generic(f.GenericFlag.Name) 70 | if err != nil { 71 | return err 72 | } 73 | if value != nil { 74 | eachName(f.Name, func(name string) { 75 | f.set.Set(f.Name, value.String()) 76 | }) 77 | } 78 | } 79 | } 80 | 81 | return nil 82 | } 83 | 84 | // ApplyInputSourceValue applies a StringSlice value to the flagSet if required 85 | func (f *StringSliceFlag) ApplyInputSourceValue(context *cli.Context, isc InputSourceContext) error { 86 | if f.set != nil { 87 | if !context.IsSet(f.Name) && !isEnvVarSet(f.EnvVar) { 88 | value, err := isc.StringSlice(f.StringSliceFlag.Name) 89 | if err != nil { 90 | return err 91 | } 92 | if value != nil { 93 | var sliceValue cli.StringSlice = value 94 | eachName(f.Name, func(name string) { 95 | underlyingFlag := f.set.Lookup(f.Name) 96 | if underlyingFlag != nil { 97 | underlyingFlag.Value = &sliceValue 98 | } 99 | }) 100 | } 101 | } 102 | } 103 | return nil 104 | } 105 | 106 | // ApplyInputSourceValue applies a IntSlice value if required 107 | func (f *IntSliceFlag) ApplyInputSourceValue(context *cli.Context, isc InputSourceContext) error { 108 | if f.set != nil { 109 | if !context.IsSet(f.Name) && !isEnvVarSet(f.EnvVar) { 110 | value, err := isc.IntSlice(f.IntSliceFlag.Name) 111 | if err != nil { 112 | return err 113 | } 114 | if value != nil { 115 | var sliceValue cli.IntSlice = value 116 | eachName(f.Name, func(name string) { 117 | underlyingFlag := f.set.Lookup(f.Name) 118 | if underlyingFlag != nil { 119 | underlyingFlag.Value = &sliceValue 120 | } 121 | }) 122 | } 123 | } 124 | } 125 | return nil 126 | } 127 | 128 | // ApplyInputSourceValue applies a Bool value to the flagSet if required 129 | func (f *BoolFlag) ApplyInputSourceValue(context *cli.Context, isc InputSourceContext) error { 130 | if f.set != nil { 131 | if !context.IsSet(f.Name) && !isEnvVarSet(f.EnvVar) { 132 | value, err := isc.Bool(f.BoolFlag.Name) 133 | if err != nil { 134 | return err 135 | } 136 | if value { 137 | eachName(f.Name, func(name string) { 138 | f.set.Set(f.Name, strconv.FormatBool(value)) 139 | }) 140 | } 141 | } 142 | } 143 | return nil 144 | } 145 | 146 | // ApplyInputSourceValue applies a BoolT value to the flagSet if required 147 | func (f *BoolTFlag) ApplyInputSourceValue(context *cli.Context, isc InputSourceContext) error { 148 | if f.set != nil { 149 | if !context.IsSet(f.Name) && !isEnvVarSet(f.EnvVar) { 150 | value, err := isc.BoolT(f.BoolTFlag.Name) 151 | if err != nil { 152 | return err 153 | } 154 | if !value { 155 | eachName(f.Name, func(name string) { 156 | f.set.Set(f.Name, strconv.FormatBool(value)) 157 | }) 158 | } 159 | } 160 | } 161 | return nil 162 | } 163 | 164 | // ApplyInputSourceValue applies a String value to the flagSet if required 165 | func (f *StringFlag) ApplyInputSourceValue(context *cli.Context, isc InputSourceContext) error { 166 | if f.set != nil { 167 | if !(context.IsSet(f.Name) || isEnvVarSet(f.EnvVar)) { 168 | value, err := isc.String(f.StringFlag.Name) 169 | if err != nil { 170 | return err 171 | } 172 | if value != "" { 173 | eachName(f.Name, func(name string) { 174 | f.set.Set(f.Name, value) 175 | }) 176 | } 177 | } 178 | } 179 | return nil 180 | } 181 | 182 | // ApplyInputSourceValue applies a int value to the flagSet if required 183 | func (f *IntFlag) ApplyInputSourceValue(context *cli.Context, isc InputSourceContext) error { 184 | if f.set != nil { 185 | if !(context.IsSet(f.Name) || isEnvVarSet(f.EnvVar)) { 186 | value, err := isc.Int(f.IntFlag.Name) 187 | if err != nil { 188 | return err 189 | } 190 | if value > 0 { 191 | eachName(f.Name, func(name string) { 192 | f.set.Set(f.Name, strconv.FormatInt(int64(value), 10)) 193 | }) 194 | } 195 | } 196 | } 197 | return nil 198 | } 199 | 200 | // ApplyInputSourceValue applies a Duration value to the flagSet if required 201 | func (f *DurationFlag) ApplyInputSourceValue(context *cli.Context, isc InputSourceContext) error { 202 | if f.set != nil { 203 | if !(context.IsSet(f.Name) || isEnvVarSet(f.EnvVar)) { 204 | value, err := isc.Duration(f.DurationFlag.Name) 205 | if err != nil { 206 | return err 207 | } 208 | if value > 0 { 209 | eachName(f.Name, func(name string) { 210 | f.set.Set(f.Name, value.String()) 211 | }) 212 | } 213 | } 214 | } 215 | return nil 216 | } 217 | 218 | // ApplyInputSourceValue applies a Float64 value to the flagSet if required 219 | func (f *Float64Flag) ApplyInputSourceValue(context *cli.Context, isc InputSourceContext) error { 220 | if f.set != nil { 221 | if !(context.IsSet(f.Name) || isEnvVarSet(f.EnvVar)) { 222 | value, err := isc.Float64(f.Float64Flag.Name) 223 | if err != nil { 224 | return err 225 | } 226 | if value > 0 { 227 | floatStr := float64ToString(value) 228 | eachName(f.Name, func(name string) { 229 | f.set.Set(f.Name, floatStr) 230 | }) 231 | } 232 | } 233 | } 234 | return nil 235 | } 236 | 237 | func isEnvVarSet(envVars string) bool { 238 | for _, envVar := range strings.Split(envVars, ",") { 239 | envVar = strings.TrimSpace(envVar) 240 | if _, ok := syscall.Getenv(envVar); ok { 241 | // TODO: Can't use this for bools as 242 | // set means that it was true or false based on 243 | // Bool flag type, should work for other types 244 | return true 245 | } 246 | } 247 | 248 | return false 249 | } 250 | 251 | func float64ToString(f float64) string { 252 | return fmt.Sprintf("%v", f) 253 | } 254 | 255 | func eachName(longName string, fn func(string)) { 256 | parts := strings.Split(longName, ",") 257 | for _, name := range parts { 258 | name = strings.Trim(name, " ") 259 | fn(name) 260 | } 261 | } 262 | -------------------------------------------------------------------------------- /src/gopkg.in/urfave/cli.v1/altsrc/helpers_test.go: -------------------------------------------------------------------------------- 1 | package altsrc 2 | 3 | import ( 4 | "reflect" 5 | "testing" 6 | ) 7 | 8 | func expect(t *testing.T, a interface{}, b interface{}) { 9 | if !reflect.DeepEqual(b, a) { 10 | t.Errorf("Expected %#v (type %v) - Got %#v (type %v)", b, reflect.TypeOf(b), a, reflect.TypeOf(a)) 11 | } 12 | } 13 | 14 | func refute(t *testing.T, a interface{}, b interface{}) { 15 | if a == b { 16 | t.Errorf("Did not expect %v (type %v) - Got %v (type %v)", b, reflect.TypeOf(b), a, reflect.TypeOf(a)) 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/gopkg.in/urfave/cli.v1/altsrc/input_source_context.go: -------------------------------------------------------------------------------- 1 | package altsrc 2 | 3 | import ( 4 | "time" 5 | 6 | "gopkg.in/urfave/cli.v1" 7 | ) 8 | 9 | // InputSourceContext is an interface used to allow 10 | // other input sources to be implemented as needed. 11 | type InputSourceContext interface { 12 | Int(name string) (int, error) 13 | Duration(name string) (time.Duration, error) 14 | Float64(name string) (float64, error) 15 | String(name string) (string, error) 16 | StringSlice(name string) ([]string, error) 17 | IntSlice(name string) ([]int, error) 18 | Generic(name string) (cli.Generic, error) 19 | Bool(name string) (bool, error) 20 | BoolT(name string) (bool, error) 21 | } 22 | -------------------------------------------------------------------------------- /src/gopkg.in/urfave/cli.v1/altsrc/map_input_source.go: -------------------------------------------------------------------------------- 1 | package altsrc 2 | 3 | import ( 4 | "fmt" 5 | "reflect" 6 | "strings" 7 | "time" 8 | 9 | "gopkg.in/urfave/cli.v1" 10 | ) 11 | 12 | // MapInputSource implements InputSourceContext to return 13 | // data from the map that is loaded. 14 | type MapInputSource struct { 15 | valueMap map[interface{}]interface{} 16 | } 17 | 18 | // nestedVal checks if the name has '.' delimiters. 19 | // If so, it tries to traverse the tree by the '.' delimited sections to find 20 | // a nested value for the key. 21 | func nestedVal(name string, tree map[interface{}]interface{}) (interface{}, bool) { 22 | if sections := strings.Split(name, "."); len(sections) > 1 { 23 | node := tree 24 | for _, section := range sections[:len(sections)-1] { 25 | if child, ok := node[section]; !ok { 26 | return nil, false 27 | } else { 28 | if ctype, ok := child.(map[interface{}]interface{}); !ok { 29 | return nil, false 30 | } else { 31 | node = ctype 32 | } 33 | } 34 | } 35 | if val, ok := node[sections[len(sections)-1]]; ok { 36 | return val, true 37 | } 38 | } 39 | return nil, false 40 | } 41 | 42 | // Int returns an int from the map if it exists otherwise returns 0 43 | func (fsm *MapInputSource) Int(name string) (int, error) { 44 | otherGenericValue, exists := fsm.valueMap[name] 45 | if exists { 46 | otherValue, isType := otherGenericValue.(int) 47 | if !isType { 48 | return 0, incorrectTypeForFlagError(name, "int", otherGenericValue) 49 | } 50 | return otherValue, nil 51 | } 52 | nestedGenericValue, exists := nestedVal(name, fsm.valueMap) 53 | if exists { 54 | otherValue, isType := nestedGenericValue.(int) 55 | if !isType { 56 | return 0, incorrectTypeForFlagError(name, "int", nestedGenericValue) 57 | } 58 | return otherValue, nil 59 | } 60 | 61 | return 0, nil 62 | } 63 | 64 | // Duration returns a duration from the map if it exists otherwise returns 0 65 | func (fsm *MapInputSource) Duration(name string) (time.Duration, error) { 66 | otherGenericValue, exists := fsm.valueMap[name] 67 | if exists { 68 | otherValue, isType := otherGenericValue.(time.Duration) 69 | if !isType { 70 | return 0, incorrectTypeForFlagError(name, "duration", otherGenericValue) 71 | } 72 | return otherValue, nil 73 | } 74 | nestedGenericValue, exists := nestedVal(name, fsm.valueMap) 75 | if exists { 76 | otherValue, isType := nestedGenericValue.(time.Duration) 77 | if !isType { 78 | return 0, incorrectTypeForFlagError(name, "duration", nestedGenericValue) 79 | } 80 | return otherValue, nil 81 | } 82 | 83 | return 0, nil 84 | } 85 | 86 | // Float64 returns an float64 from the map if it exists otherwise returns 0 87 | func (fsm *MapInputSource) Float64(name string) (float64, error) { 88 | otherGenericValue, exists := fsm.valueMap[name] 89 | if exists { 90 | otherValue, isType := otherGenericValue.(float64) 91 | if !isType { 92 | return 0, incorrectTypeForFlagError(name, "float64", otherGenericValue) 93 | } 94 | return otherValue, nil 95 | } 96 | nestedGenericValue, exists := nestedVal(name, fsm.valueMap) 97 | if exists { 98 | otherValue, isType := nestedGenericValue.(float64) 99 | if !isType { 100 | return 0, incorrectTypeForFlagError(name, "float64", nestedGenericValue) 101 | } 102 | return otherValue, nil 103 | } 104 | 105 | return 0, nil 106 | } 107 | 108 | // String returns a string from the map if it exists otherwise returns an empty string 109 | func (fsm *MapInputSource) String(name string) (string, error) { 110 | otherGenericValue, exists := fsm.valueMap[name] 111 | if exists { 112 | otherValue, isType := otherGenericValue.(string) 113 | if !isType { 114 | return "", incorrectTypeForFlagError(name, "string", otherGenericValue) 115 | } 116 | return otherValue, nil 117 | } 118 | nestedGenericValue, exists := nestedVal(name, fsm.valueMap) 119 | if exists { 120 | otherValue, isType := nestedGenericValue.(string) 121 | if !isType { 122 | return "", incorrectTypeForFlagError(name, "string", nestedGenericValue) 123 | } 124 | return otherValue, nil 125 | } 126 | 127 | return "", nil 128 | } 129 | 130 | // StringSlice returns an []string from the map if it exists otherwise returns nil 131 | func (fsm *MapInputSource) StringSlice(name string) ([]string, error) { 132 | otherGenericValue, exists := fsm.valueMap[name] 133 | if exists { 134 | otherValue, isType := otherGenericValue.([]string) 135 | if !isType { 136 | return nil, incorrectTypeForFlagError(name, "[]string", otherGenericValue) 137 | } 138 | return otherValue, nil 139 | } 140 | nestedGenericValue, exists := nestedVal(name, fsm.valueMap) 141 | if exists { 142 | otherValue, isType := nestedGenericValue.([]string) 143 | if !isType { 144 | return nil, incorrectTypeForFlagError(name, "[]string", nestedGenericValue) 145 | } 146 | return otherValue, nil 147 | } 148 | 149 | return nil, nil 150 | } 151 | 152 | // IntSlice returns an []int from the map if it exists otherwise returns nil 153 | func (fsm *MapInputSource) IntSlice(name string) ([]int, error) { 154 | otherGenericValue, exists := fsm.valueMap[name] 155 | if exists { 156 | otherValue, isType := otherGenericValue.([]int) 157 | if !isType { 158 | return nil, incorrectTypeForFlagError(name, "[]int", otherGenericValue) 159 | } 160 | return otherValue, nil 161 | } 162 | nestedGenericValue, exists := nestedVal(name, fsm.valueMap) 163 | if exists { 164 | otherValue, isType := nestedGenericValue.([]int) 165 | if !isType { 166 | return nil, incorrectTypeForFlagError(name, "[]int", nestedGenericValue) 167 | } 168 | return otherValue, nil 169 | } 170 | 171 | return nil, nil 172 | } 173 | 174 | // Generic returns an cli.Generic from the map if it exists otherwise returns nil 175 | func (fsm *MapInputSource) Generic(name string) (cli.Generic, error) { 176 | otherGenericValue, exists := fsm.valueMap[name] 177 | if exists { 178 | otherValue, isType := otherGenericValue.(cli.Generic) 179 | if !isType { 180 | return nil, incorrectTypeForFlagError(name, "cli.Generic", otherGenericValue) 181 | } 182 | return otherValue, nil 183 | } 184 | nestedGenericValue, exists := nestedVal(name, fsm.valueMap) 185 | if exists { 186 | otherValue, isType := nestedGenericValue.(cli.Generic) 187 | if !isType { 188 | return nil, incorrectTypeForFlagError(name, "cli.Generic", nestedGenericValue) 189 | } 190 | return otherValue, nil 191 | } 192 | 193 | return nil, nil 194 | } 195 | 196 | // Bool returns an bool from the map otherwise returns false 197 | func (fsm *MapInputSource) Bool(name string) (bool, error) { 198 | otherGenericValue, exists := fsm.valueMap[name] 199 | if exists { 200 | otherValue, isType := otherGenericValue.(bool) 201 | if !isType { 202 | return false, incorrectTypeForFlagError(name, "bool", otherGenericValue) 203 | } 204 | return otherValue, nil 205 | } 206 | nestedGenericValue, exists := nestedVal(name, fsm.valueMap) 207 | if exists { 208 | otherValue, isType := nestedGenericValue.(bool) 209 | if !isType { 210 | return false, incorrectTypeForFlagError(name, "bool", nestedGenericValue) 211 | } 212 | return otherValue, nil 213 | } 214 | 215 | return false, nil 216 | } 217 | 218 | // BoolT returns an bool from the map otherwise returns true 219 | func (fsm *MapInputSource) BoolT(name string) (bool, error) { 220 | otherGenericValue, exists := fsm.valueMap[name] 221 | if exists { 222 | otherValue, isType := otherGenericValue.(bool) 223 | if !isType { 224 | return true, incorrectTypeForFlagError(name, "bool", otherGenericValue) 225 | } 226 | return otherValue, nil 227 | } 228 | nestedGenericValue, exists := nestedVal(name, fsm.valueMap) 229 | if exists { 230 | otherValue, isType := nestedGenericValue.(bool) 231 | if !isType { 232 | return true, incorrectTypeForFlagError(name, "bool", nestedGenericValue) 233 | } 234 | return otherValue, nil 235 | } 236 | 237 | return true, nil 238 | } 239 | 240 | func incorrectTypeForFlagError(name, expectedTypeName string, value interface{}) error { 241 | valueType := reflect.TypeOf(value) 242 | valueTypeName := "" 243 | if valueType != nil { 244 | valueTypeName = valueType.Name() 245 | } 246 | 247 | return fmt.Errorf("Mismatched type for flag '%s'. Expected '%s' but actual is '%s'", name, expectedTypeName, valueTypeName) 248 | } 249 | -------------------------------------------------------------------------------- /src/gopkg.in/urfave/cli.v1/altsrc/toml_file_loader.go: -------------------------------------------------------------------------------- 1 | // Disabling building of toml support in cases where golang is 1.0 or 1.1 2 | // as the encoding library is not implemented or supported. 3 | 4 | // +build go1.2 5 | 6 | package altsrc 7 | 8 | import ( 9 | "fmt" 10 | "reflect" 11 | 12 | "github.com/BurntSushi/toml" 13 | "gopkg.in/urfave/cli.v1" 14 | ) 15 | 16 | type tomlMap struct { 17 | Map map[interface{}]interface{} 18 | } 19 | 20 | func unmarshalMap(i interface{}) (ret map[interface{}]interface{}, err error) { 21 | ret = make(map[interface{}]interface{}) 22 | m := i.(map[string]interface{}) 23 | for key, val := range m { 24 | v := reflect.ValueOf(val) 25 | switch v.Kind() { 26 | case reflect.Bool: 27 | ret[key] = val.(bool) 28 | case reflect.String: 29 | ret[key] = val.(string) 30 | case reflect.Int: 31 | ret[key] = int(val.(int)) 32 | case reflect.Int8: 33 | ret[key] = int(val.(int8)) 34 | case reflect.Int16: 35 | ret[key] = int(val.(int16)) 36 | case reflect.Int32: 37 | ret[key] = int(val.(int32)) 38 | case reflect.Int64: 39 | ret[key] = int(val.(int64)) 40 | case reflect.Uint: 41 | ret[key] = int(val.(uint)) 42 | case reflect.Uint8: 43 | ret[key] = int(val.(uint8)) 44 | case reflect.Uint16: 45 | ret[key] = int(val.(uint16)) 46 | case reflect.Uint32: 47 | ret[key] = int(val.(uint32)) 48 | case reflect.Uint64: 49 | ret[key] = int(val.(uint64)) 50 | case reflect.Float32: 51 | ret[key] = float64(val.(float32)) 52 | case reflect.Float64: 53 | ret[key] = float64(val.(float64)) 54 | case reflect.Map: 55 | if tmp, err := unmarshalMap(val); err == nil { 56 | ret[key] = tmp 57 | } else { 58 | return nil, err 59 | } 60 | case reflect.Array: 61 | fallthrough // [todo] - Support array type 62 | default: 63 | return nil, fmt.Errorf("Unsupported: type = %#v", v.Kind()) 64 | } 65 | } 66 | return ret, nil 67 | } 68 | 69 | func (self *tomlMap) UnmarshalTOML(i interface{}) error { 70 | if tmp, err := unmarshalMap(i); err == nil { 71 | self.Map = tmp 72 | } else { 73 | return err 74 | } 75 | return nil 76 | } 77 | 78 | type tomlSourceContext struct { 79 | FilePath string 80 | } 81 | 82 | // NewTomlSourceFromFile creates a new TOML InputSourceContext from a filepath. 83 | func NewTomlSourceFromFile(file string) (InputSourceContext, error) { 84 | tsc := &tomlSourceContext{FilePath: file} 85 | var results tomlMap = tomlMap{} 86 | if err := readCommandToml(tsc.FilePath, &results); err != nil { 87 | return nil, fmt.Errorf("Unable to load TOML file '%s': inner error: \n'%v'", tsc.FilePath, err.Error()) 88 | } 89 | return &MapInputSource{valueMap: results.Map}, nil 90 | } 91 | 92 | // NewTomlSourceFromFlagFunc creates a new TOML InputSourceContext from a provided flag name and source context. 93 | func NewTomlSourceFromFlagFunc(flagFileName string) func(context *cli.Context) (InputSourceContext, error) { 94 | return func(context *cli.Context) (InputSourceContext, error) { 95 | filePath := context.String(flagFileName) 96 | return NewTomlSourceFromFile(filePath) 97 | } 98 | } 99 | 100 | func readCommandToml(filePath string, container interface{}) (err error) { 101 | b, err := loadDataFrom(filePath) 102 | if err != nil { 103 | return err 104 | } 105 | 106 | err = toml.Unmarshal(b, container) 107 | if err != nil { 108 | return err 109 | } 110 | 111 | err = nil 112 | return 113 | } 114 | -------------------------------------------------------------------------------- /src/gopkg.in/urfave/cli.v1/altsrc/yaml_file_loader.go: -------------------------------------------------------------------------------- 1 | // Disabling building of yaml support in cases where golang is 1.0 or 1.1 2 | // as the encoding library is not implemented or supported. 3 | 4 | // +build go1.2 5 | 6 | package altsrc 7 | 8 | import ( 9 | "fmt" 10 | "io/ioutil" 11 | "net/http" 12 | "net/url" 13 | "os" 14 | 15 | "gopkg.in/urfave/cli.v1" 16 | 17 | "gopkg.in/yaml.v2" 18 | ) 19 | 20 | type yamlSourceContext struct { 21 | FilePath string 22 | } 23 | 24 | // NewYamlSourceFromFile creates a new Yaml InputSourceContext from a filepath. 25 | func NewYamlSourceFromFile(file string) (InputSourceContext, error) { 26 | ysc := &yamlSourceContext{FilePath: file} 27 | var results map[interface{}]interface{} 28 | err := readCommandYaml(ysc.FilePath, &results) 29 | if err != nil { 30 | return nil, fmt.Errorf("Unable to load Yaml file '%s': inner error: \n'%v'", ysc.FilePath, err.Error()) 31 | } 32 | 33 | return &MapInputSource{valueMap: results}, nil 34 | } 35 | 36 | // NewYamlSourceFromFlagFunc creates a new Yaml InputSourceContext from a provided flag name and source context. 37 | func NewYamlSourceFromFlagFunc(flagFileName string) func(context *cli.Context) (InputSourceContext, error) { 38 | return func(context *cli.Context) (InputSourceContext, error) { 39 | filePath := context.String(flagFileName) 40 | return NewYamlSourceFromFile(filePath) 41 | } 42 | } 43 | 44 | func readCommandYaml(filePath string, container interface{}) (err error) { 45 | b, err := loadDataFrom(filePath) 46 | if err != nil { 47 | return err 48 | } 49 | 50 | err = yaml.Unmarshal(b, container) 51 | if err != nil { 52 | return err 53 | } 54 | 55 | err = nil 56 | return 57 | } 58 | 59 | func loadDataFrom(filePath string) ([]byte, error) { 60 | u, err := url.Parse(filePath) 61 | if err != nil { 62 | return nil, err 63 | } 64 | 65 | if u.Host != "" { // i have a host, now do i support the scheme? 66 | switch u.Scheme { 67 | case "http", "https": 68 | res, err := http.Get(filePath) 69 | if err != nil { 70 | return nil, err 71 | } 72 | return ioutil.ReadAll(res.Body) 73 | default: 74 | return nil, fmt.Errorf("scheme of %s is unsupported", filePath) 75 | } 76 | } else if u.Path != "" { // i dont have a host, but I have a path. I am a local file. 77 | if _, notFoundFileErr := os.Stat(filePath); notFoundFileErr != nil { 78 | return nil, fmt.Errorf("Cannot read from file: '%s' because it does not exist.", filePath) 79 | } 80 | return ioutil.ReadFile(filePath) 81 | } else { 82 | return nil, fmt.Errorf("unable to determine how to load from path %s", filePath) 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /src/gopkg.in/urfave/cli.v1/appveyor.yml: -------------------------------------------------------------------------------- 1 | version: "{build}" 2 | 3 | os: Windows Server 2012 R2 4 | 5 | clone_folder: c:\gopath\src\github.com\urfave\cli 6 | 7 | environment: 8 | GOPATH: C:\gopath 9 | GOVERSION: 1.6 10 | PYTHON: C:\Python27-x64 11 | PYTHON_VERSION: 2.7.x 12 | PYTHON_ARCH: 64 13 | 14 | install: 15 | - set PATH=%GOPATH%\bin;C:\go\bin;%PATH% 16 | - go version 17 | - go env 18 | - go get github.com/urfave/gfmrun/... 19 | - go get -v -t ./... 20 | 21 | build_script: 22 | - python runtests vet 23 | - python runtests test 24 | - python runtests gfmrun 25 | -------------------------------------------------------------------------------- /src/gopkg.in/urfave/cli.v1/autocomplete/bash_autocomplete: -------------------------------------------------------------------------------- 1 | #! /bin/bash 2 | 3 | : ${PROG:=$(basename ${BASH_SOURCE})} 4 | 5 | _cli_bash_autocomplete() { 6 | local cur opts base 7 | COMPREPLY=() 8 | cur="${COMP_WORDS[COMP_CWORD]}" 9 | opts=$( ${COMP_WORDS[@]:0:$COMP_CWORD} --generate-bash-completion ) 10 | COMPREPLY=( $(compgen -W "${opts}" -- ${cur}) ) 11 | return 0 12 | } 13 | 14 | complete -F _cli_bash_autocomplete $PROG 15 | -------------------------------------------------------------------------------- /src/gopkg.in/urfave/cli.v1/autocomplete/zsh_autocomplete: -------------------------------------------------------------------------------- 1 | autoload -U compinit && compinit 2 | autoload -U bashcompinit && bashcompinit 3 | 4 | script_dir=$(dirname $0) 5 | source ${script_dir}/bash_autocomplete 6 | -------------------------------------------------------------------------------- /src/gopkg.in/urfave/cli.v1/category.go: -------------------------------------------------------------------------------- 1 | package cli 2 | 3 | // CommandCategories is a slice of *CommandCategory. 4 | type CommandCategories []*CommandCategory 5 | 6 | // CommandCategory is a category containing commands. 7 | type CommandCategory struct { 8 | Name string 9 | Commands Commands 10 | } 11 | 12 | func (c CommandCategories) Less(i, j int) bool { 13 | return c[i].Name < c[j].Name 14 | } 15 | 16 | func (c CommandCategories) Len() int { 17 | return len(c) 18 | } 19 | 20 | func (c CommandCategories) Swap(i, j int) { 21 | c[i], c[j] = c[j], c[i] 22 | } 23 | 24 | // AddCommand adds a command to a category. 25 | func (c CommandCategories) AddCommand(category string, command Command) CommandCategories { 26 | for _, commandCategory := range c { 27 | if commandCategory.Name == category { 28 | commandCategory.Commands = append(commandCategory.Commands, command) 29 | return c 30 | } 31 | } 32 | return append(c, &CommandCategory{Name: category, Commands: []Command{command}}) 33 | } 34 | 35 | // VisibleCommands returns a slice of the Commands with Hidden=false 36 | func (c *CommandCategory) VisibleCommands() []Command { 37 | ret := []Command{} 38 | for _, command := range c.Commands { 39 | if !command.Hidden { 40 | ret = append(ret, command) 41 | } 42 | } 43 | return ret 44 | } 45 | -------------------------------------------------------------------------------- /src/gopkg.in/urfave/cli.v1/cli.go: -------------------------------------------------------------------------------- 1 | // Package cli provides a minimal framework for creating and organizing command line 2 | // Go applications. cli is designed to be easy to understand and write, the most simple 3 | // cli application can be written as follows: 4 | // func main() { 5 | // cli.NewApp().Run(os.Args) 6 | // } 7 | // 8 | // Of course this application does not do much, so let's make this an actual application: 9 | // func main() { 10 | // app := cli.NewApp() 11 | // app.Name = "greet" 12 | // app.Usage = "say a greeting" 13 | // app.Action = func(c *cli.Context) error { 14 | // println("Greetings") 15 | // } 16 | // 17 | // app.Run(os.Args) 18 | // } 19 | package cli 20 | 21 | //go:generate python ./generate-flag-types cli -i flag-types.json -o flag_generated.go 22 | -------------------------------------------------------------------------------- /src/gopkg.in/urfave/cli.v1/command.go: -------------------------------------------------------------------------------- 1 | package cli 2 | 3 | import ( 4 | "fmt" 5 | "io/ioutil" 6 | "sort" 7 | "strings" 8 | ) 9 | 10 | // Command is a subcommand for a cli.App. 11 | type Command struct { 12 | // The name of the command 13 | Name string 14 | // short name of the command. Typically one character (deprecated, use `Aliases`) 15 | ShortName string 16 | // A list of aliases for the command 17 | Aliases []string 18 | // A short description of the usage of this command 19 | Usage string 20 | // Custom text to show on USAGE section of help 21 | UsageText string 22 | // A longer explanation of how the command works 23 | Description string 24 | // A short description of the arguments of this command 25 | ArgsUsage string 26 | // The category the command is part of 27 | Category string 28 | // The function to call when checking for bash command completions 29 | BashComplete BashCompleteFunc 30 | // An action to execute before any sub-subcommands are run, but after the context is ready 31 | // If a non-nil error is returned, no sub-subcommands are run 32 | Before BeforeFunc 33 | // An action to execute after any subcommands are run, but after the subcommand has finished 34 | // It is run even if Action() panics 35 | After AfterFunc 36 | // The function to call when this command is invoked 37 | Action interface{} 38 | // TODO: replace `Action: interface{}` with `Action: ActionFunc` once some kind 39 | // of deprecation period has passed, maybe? 40 | 41 | // Execute this function if a usage error occurs. 42 | OnUsageError OnUsageErrorFunc 43 | // List of child commands 44 | Subcommands Commands 45 | // List of flags to parse 46 | Flags []Flag 47 | // Treat all flags as normal arguments if true 48 | SkipFlagParsing bool 49 | // Skip argument reordering which attempts to move flags before arguments, 50 | // but only works if all flags appear after all arguments. This behavior was 51 | // removed n version 2 since it only works under specific conditions so we 52 | // backport here by exposing it as an option for compatibility. 53 | SkipArgReorder bool 54 | // Boolean to hide built-in help command 55 | HideHelp bool 56 | // Boolean to hide this command from help or completion 57 | Hidden bool 58 | 59 | // Full name of command for help, defaults to full command name, including parent commands. 60 | HelpName string 61 | commandNamePath []string 62 | } 63 | 64 | // FullName returns the full name of the command. 65 | // For subcommands this ensures that parent commands are part of the command path 66 | func (c Command) FullName() string { 67 | if c.commandNamePath == nil { 68 | return c.Name 69 | } 70 | return strings.Join(c.commandNamePath, " ") 71 | } 72 | 73 | // Commands is a slice of Command 74 | type Commands []Command 75 | 76 | // Run invokes the command given the context, parses ctx.Args() to generate command-specific flags 77 | func (c Command) Run(ctx *Context) (err error) { 78 | if len(c.Subcommands) > 0 { 79 | return c.startApp(ctx) 80 | } 81 | 82 | if !c.HideHelp && (HelpFlag != BoolFlag{}) { 83 | // append help to flags 84 | c.Flags = append( 85 | c.Flags, 86 | HelpFlag, 87 | ) 88 | } 89 | 90 | set, err := flagSet(c.Name, c.Flags) 91 | if err != nil { 92 | return err 93 | } 94 | set.SetOutput(ioutil.Discard) 95 | 96 | if c.SkipFlagParsing { 97 | err = set.Parse(append([]string{"--"}, ctx.Args().Tail()...)) 98 | } else if !c.SkipArgReorder { 99 | firstFlagIndex := -1 100 | terminatorIndex := -1 101 | for index, arg := range ctx.Args() { 102 | if arg == "--" { 103 | terminatorIndex = index 104 | break 105 | } else if arg == "-" { 106 | // Do nothing. A dash alone is not really a flag. 107 | continue 108 | } else if strings.HasPrefix(arg, "-") && firstFlagIndex == -1 { 109 | firstFlagIndex = index 110 | } 111 | } 112 | 113 | if firstFlagIndex > -1 { 114 | args := ctx.Args() 115 | regularArgs := make([]string, len(args[1:firstFlagIndex])) 116 | copy(regularArgs, args[1:firstFlagIndex]) 117 | 118 | var flagArgs []string 119 | if terminatorIndex > -1 { 120 | flagArgs = args[firstFlagIndex:terminatorIndex] 121 | regularArgs = append(regularArgs, args[terminatorIndex:]...) 122 | } else { 123 | flagArgs = args[firstFlagIndex:] 124 | } 125 | 126 | err = set.Parse(append(flagArgs, regularArgs...)) 127 | } else { 128 | err = set.Parse(ctx.Args().Tail()) 129 | } 130 | } else { 131 | err = set.Parse(ctx.Args().Tail()) 132 | } 133 | 134 | nerr := normalizeFlags(c.Flags, set) 135 | if nerr != nil { 136 | fmt.Fprintln(ctx.App.Writer, nerr) 137 | fmt.Fprintln(ctx.App.Writer) 138 | ShowCommandHelp(ctx, c.Name) 139 | return nerr 140 | } 141 | 142 | context := NewContext(ctx.App, set, ctx) 143 | if checkCommandCompletions(context, c.Name) { 144 | return nil 145 | } 146 | 147 | if err != nil { 148 | if c.OnUsageError != nil { 149 | err := c.OnUsageError(ctx, err, false) 150 | HandleExitCoder(err) 151 | return err 152 | } 153 | fmt.Fprintln(ctx.App.Writer, "Incorrect Usage:", err.Error()) 154 | fmt.Fprintln(ctx.App.Writer) 155 | ShowCommandHelp(ctx, c.Name) 156 | return err 157 | } 158 | 159 | if checkCommandHelp(context, c.Name) { 160 | return nil 161 | } 162 | 163 | if c.After != nil { 164 | defer func() { 165 | afterErr := c.After(context) 166 | if afterErr != nil { 167 | HandleExitCoder(err) 168 | if err != nil { 169 | err = NewMultiError(err, afterErr) 170 | } else { 171 | err = afterErr 172 | } 173 | } 174 | }() 175 | } 176 | 177 | if c.Before != nil { 178 | err = c.Before(context) 179 | if err != nil { 180 | fmt.Fprintln(ctx.App.Writer, err) 181 | fmt.Fprintln(ctx.App.Writer) 182 | ShowCommandHelp(ctx, c.Name) 183 | HandleExitCoder(err) 184 | return err 185 | } 186 | } 187 | 188 | if c.Action == nil { 189 | c.Action = helpSubcommand.Action 190 | } 191 | 192 | context.Command = c 193 | err = HandleAction(c.Action, context) 194 | 195 | if err != nil { 196 | HandleExitCoder(err) 197 | } 198 | return err 199 | } 200 | 201 | // Names returns the names including short names and aliases. 202 | func (c Command) Names() []string { 203 | names := []string{c.Name} 204 | 205 | if c.ShortName != "" { 206 | names = append(names, c.ShortName) 207 | } 208 | 209 | return append(names, c.Aliases...) 210 | } 211 | 212 | // HasName returns true if Command.Name or Command.ShortName matches given name 213 | func (c Command) HasName(name string) bool { 214 | for _, n := range c.Names() { 215 | if n == name { 216 | return true 217 | } 218 | } 219 | return false 220 | } 221 | 222 | func (c Command) startApp(ctx *Context) error { 223 | app := NewApp() 224 | app.Metadata = ctx.App.Metadata 225 | // set the name and usage 226 | app.Name = fmt.Sprintf("%s %s", ctx.App.Name, c.Name) 227 | if c.HelpName == "" { 228 | app.HelpName = c.HelpName 229 | } else { 230 | app.HelpName = app.Name 231 | } 232 | 233 | if c.Description != "" { 234 | app.Usage = c.Description 235 | } else { 236 | app.Usage = c.Usage 237 | } 238 | 239 | // set CommandNotFound 240 | app.CommandNotFound = ctx.App.CommandNotFound 241 | 242 | // set the flags and commands 243 | app.Commands = c.Subcommands 244 | app.Flags = c.Flags 245 | app.HideHelp = c.HideHelp 246 | 247 | app.Version = ctx.App.Version 248 | app.HideVersion = ctx.App.HideVersion 249 | app.Compiled = ctx.App.Compiled 250 | app.Author = ctx.App.Author 251 | app.Email = ctx.App.Email 252 | app.Writer = ctx.App.Writer 253 | 254 | app.categories = CommandCategories{} 255 | for _, command := range c.Subcommands { 256 | app.categories = app.categories.AddCommand(command.Category, command) 257 | } 258 | 259 | sort.Sort(app.categories) 260 | 261 | // bash completion 262 | app.EnableBashCompletion = ctx.App.EnableBashCompletion 263 | if c.BashComplete != nil { 264 | app.BashComplete = c.BashComplete 265 | } 266 | 267 | // set the actions 268 | app.Before = c.Before 269 | app.After = c.After 270 | if c.Action != nil { 271 | app.Action = c.Action 272 | } else { 273 | app.Action = helpSubcommand.Action 274 | } 275 | 276 | for index, cc := range app.Commands { 277 | app.Commands[index].commandNamePath = []string{c.Name, cc.Name} 278 | } 279 | 280 | return app.RunAsSubcommand(ctx) 281 | } 282 | 283 | // VisibleFlags returns a slice of the Flags with Hidden=false 284 | func (c Command) VisibleFlags() []Flag { 285 | return visibleFlags(c.Flags) 286 | } 287 | -------------------------------------------------------------------------------- /src/gopkg.in/urfave/cli.v1/command_test.go: -------------------------------------------------------------------------------- 1 | package cli 2 | 3 | import ( 4 | "errors" 5 | "flag" 6 | "fmt" 7 | "io/ioutil" 8 | "strings" 9 | "testing" 10 | ) 11 | 12 | func TestCommandFlagParsing(t *testing.T) { 13 | cases := []struct { 14 | testArgs []string 15 | skipFlagParsing bool 16 | skipArgReorder bool 17 | expectedErr error 18 | }{ 19 | // Test normal "not ignoring flags" flow 20 | {[]string{"test-cmd", "blah", "blah", "-break"}, false, false, errors.New("flag provided but not defined: -break")}, 21 | 22 | // Test no arg reorder 23 | {[]string{"test-cmd", "blah", "blah", "-break"}, false, true, nil}, 24 | 25 | {[]string{"test-cmd", "blah", "blah"}, true, false, nil}, // Test SkipFlagParsing without any args that look like flags 26 | {[]string{"test-cmd", "blah", "-break"}, true, false, nil}, // Test SkipFlagParsing with random flag arg 27 | {[]string{"test-cmd", "blah", "-help"}, true, false, nil}, // Test SkipFlagParsing with "special" help flag arg 28 | } 29 | 30 | for _, c := range cases { 31 | app := NewApp() 32 | app.Writer = ioutil.Discard 33 | set := flag.NewFlagSet("test", 0) 34 | set.Parse(c.testArgs) 35 | 36 | context := NewContext(app, set, nil) 37 | 38 | command := Command{ 39 | Name: "test-cmd", 40 | Aliases: []string{"tc"}, 41 | Usage: "this is for testing", 42 | Description: "testing", 43 | Action: func(_ *Context) error { return nil }, 44 | SkipFlagParsing: c.skipFlagParsing, 45 | SkipArgReorder: c.skipArgReorder, 46 | } 47 | 48 | err := command.Run(context) 49 | 50 | expect(t, err, c.expectedErr) 51 | expect(t, []string(context.Args()), c.testArgs) 52 | } 53 | } 54 | 55 | func TestCommand_Run_DoesNotOverwriteErrorFromBefore(t *testing.T) { 56 | app := NewApp() 57 | app.Commands = []Command{ 58 | { 59 | Name: "bar", 60 | Before: func(c *Context) error { 61 | return fmt.Errorf("before error") 62 | }, 63 | After: func(c *Context) error { 64 | return fmt.Errorf("after error") 65 | }, 66 | }, 67 | } 68 | 69 | err := app.Run([]string{"foo", "bar"}) 70 | if err == nil { 71 | t.Fatalf("expected to receive error from Run, got none") 72 | } 73 | 74 | if !strings.Contains(err.Error(), "before error") { 75 | t.Errorf("expected text of error from Before method, but got none in \"%v\"", err) 76 | } 77 | if !strings.Contains(err.Error(), "after error") { 78 | t.Errorf("expected text of error from After method, but got none in \"%v\"", err) 79 | } 80 | } 81 | 82 | func TestCommand_Run_BeforeSavesMetadata(t *testing.T) { 83 | var receivedMsgFromAction string 84 | var receivedMsgFromAfter string 85 | 86 | app := NewApp() 87 | app.Commands = []Command{ 88 | { 89 | Name: "bar", 90 | Before: func(c *Context) error { 91 | c.App.Metadata["msg"] = "hello world" 92 | return nil 93 | }, 94 | Action: func(c *Context) error { 95 | msg, ok := c.App.Metadata["msg"] 96 | if !ok { 97 | return errors.New("msg not found") 98 | } 99 | receivedMsgFromAction = msg.(string) 100 | return nil 101 | }, 102 | After: func(c *Context) error { 103 | msg, ok := c.App.Metadata["msg"] 104 | if !ok { 105 | return errors.New("msg not found") 106 | } 107 | receivedMsgFromAfter = msg.(string) 108 | return nil 109 | }, 110 | }, 111 | } 112 | 113 | err := app.Run([]string{"foo", "bar"}) 114 | if err != nil { 115 | t.Fatalf("expected no error from Run, got %s", err) 116 | } 117 | 118 | expectedMsg := "hello world" 119 | 120 | if receivedMsgFromAction != expectedMsg { 121 | t.Fatalf("expected msg from Action to match. Given: %q\nExpected: %q", 122 | receivedMsgFromAction, expectedMsg) 123 | } 124 | if receivedMsgFromAfter != expectedMsg { 125 | t.Fatalf("expected msg from After to match. Given: %q\nExpected: %q", 126 | receivedMsgFromAction, expectedMsg) 127 | } 128 | } 129 | 130 | func TestCommand_OnUsageError_WithWrongFlagValue(t *testing.T) { 131 | app := NewApp() 132 | app.Commands = []Command{ 133 | { 134 | Name: "bar", 135 | Flags: []Flag{ 136 | IntFlag{Name: "flag"}, 137 | }, 138 | OnUsageError: func(c *Context, err error, _ bool) error { 139 | if !strings.HasPrefix(err.Error(), "invalid value \"wrong\"") { 140 | t.Errorf("Expect an invalid value error, but got \"%v\"", err) 141 | } 142 | return errors.New("intercepted: " + err.Error()) 143 | }, 144 | }, 145 | } 146 | 147 | err := app.Run([]string{"foo", "bar", "--flag=wrong"}) 148 | if err == nil { 149 | t.Fatalf("expected to receive error from Run, got none") 150 | } 151 | 152 | if !strings.HasPrefix(err.Error(), "intercepted: invalid value") { 153 | t.Errorf("Expect an intercepted error, but got \"%v\"", err) 154 | } 155 | } 156 | -------------------------------------------------------------------------------- /src/gopkg.in/urfave/cli.v1/context.go: -------------------------------------------------------------------------------- 1 | package cli 2 | 3 | import ( 4 | "errors" 5 | "flag" 6 | "reflect" 7 | "strings" 8 | "syscall" 9 | ) 10 | 11 | // Context is a type that is passed through to 12 | // each Handler action in a cli application. Context 13 | // can be used to retrieve context-specific Args and 14 | // parsed command-line options. 15 | type Context struct { 16 | App *App 17 | Command Command 18 | shellComplete bool 19 | flagSet *flag.FlagSet 20 | setFlags map[string]bool 21 | parentContext *Context 22 | } 23 | 24 | // NewContext creates a new context. For use in when invoking an App or Command action. 25 | func NewContext(app *App, set *flag.FlagSet, parentCtx *Context) *Context { 26 | c := &Context{App: app, flagSet: set, parentContext: parentCtx} 27 | 28 | if parentCtx != nil { 29 | c.shellComplete = parentCtx.shellComplete 30 | } 31 | 32 | return c 33 | } 34 | 35 | // NumFlags returns the number of flags set 36 | func (c *Context) NumFlags() int { 37 | return c.flagSet.NFlag() 38 | } 39 | 40 | // Set sets a context flag to a value. 41 | func (c *Context) Set(name, value string) error { 42 | return c.flagSet.Set(name, value) 43 | } 44 | 45 | // GlobalSet sets a context flag to a value on the global flagset 46 | func (c *Context) GlobalSet(name, value string) error { 47 | return globalContext(c).flagSet.Set(name, value) 48 | } 49 | 50 | // IsSet determines if the flag was actually set 51 | func (c *Context) IsSet(name string) bool { 52 | if c.setFlags == nil { 53 | c.setFlags = make(map[string]bool) 54 | 55 | c.flagSet.Visit(func(f *flag.Flag) { 56 | c.setFlags[f.Name] = true 57 | }) 58 | 59 | c.flagSet.VisitAll(func(f *flag.Flag) { 60 | if _, ok := c.setFlags[f.Name]; ok { 61 | return 62 | } 63 | c.setFlags[f.Name] = false 64 | }) 65 | 66 | // XXX hack to support IsSet for flags with EnvVar 67 | // 68 | // There isn't an easy way to do this with the current implementation since 69 | // whether a flag was set via an environment variable is very difficult to 70 | // determine here. Instead, we intend to introduce a backwards incompatible 71 | // change in version 2 to add `IsSet` to the Flag interface to push the 72 | // responsibility closer to where the information required to determine 73 | // whether a flag is set by non-standard means such as environment 74 | // variables is avaliable. 75 | // 76 | // See https://github.com/urfave/cli/issues/294 for additional discussion 77 | flags := c.Command.Flags 78 | if c.Command.Name == "" { // cannot == Command{} since it contains slice types 79 | if c.App != nil { 80 | flags = c.App.Flags 81 | } 82 | } 83 | for _, f := range flags { 84 | eachName(f.GetName(), func(name string) { 85 | if isSet, ok := c.setFlags[name]; isSet || !ok { 86 | return 87 | } 88 | 89 | val := reflect.ValueOf(f) 90 | if val.Kind() == reflect.Ptr { 91 | val = val.Elem() 92 | } 93 | 94 | envVarValue := val.FieldByName("EnvVar") 95 | if !envVarValue.IsValid() { 96 | return 97 | } 98 | 99 | eachName(envVarValue.String(), func(envVar string) { 100 | envVar = strings.TrimSpace(envVar) 101 | if _, ok := syscall.Getenv(envVar); ok { 102 | c.setFlags[name] = true 103 | return 104 | } 105 | }) 106 | }) 107 | } 108 | } 109 | 110 | return c.setFlags[name] 111 | } 112 | 113 | // GlobalIsSet determines if the global flag was actually set 114 | func (c *Context) GlobalIsSet(name string) bool { 115 | ctx := c 116 | if ctx.parentContext != nil { 117 | ctx = ctx.parentContext 118 | } 119 | 120 | for ; ctx != nil; ctx = ctx.parentContext { 121 | if ctx.IsSet(name) { 122 | return true 123 | } 124 | } 125 | return false 126 | } 127 | 128 | // FlagNames returns a slice of flag names used in this context. 129 | func (c *Context) FlagNames() (names []string) { 130 | for _, flag := range c.Command.Flags { 131 | name := strings.Split(flag.GetName(), ",")[0] 132 | if name == "help" { 133 | continue 134 | } 135 | names = append(names, name) 136 | } 137 | return 138 | } 139 | 140 | // GlobalFlagNames returns a slice of global flag names used by the app. 141 | func (c *Context) GlobalFlagNames() (names []string) { 142 | for _, flag := range c.App.Flags { 143 | name := strings.Split(flag.GetName(), ",")[0] 144 | if name == "help" || name == "version" { 145 | continue 146 | } 147 | names = append(names, name) 148 | } 149 | return 150 | } 151 | 152 | // Parent returns the parent context, if any 153 | func (c *Context) Parent() *Context { 154 | return c.parentContext 155 | } 156 | 157 | // value returns the value of the flag coressponding to `name` 158 | func (c *Context) value(name string) interface{} { 159 | return c.flagSet.Lookup(name).Value.(flag.Getter).Get() 160 | } 161 | 162 | // Args contains apps console arguments 163 | type Args []string 164 | 165 | // Args returns the command line arguments associated with the context. 166 | func (c *Context) Args() Args { 167 | args := Args(c.flagSet.Args()) 168 | return args 169 | } 170 | 171 | // NArg returns the number of the command line arguments. 172 | func (c *Context) NArg() int { 173 | return len(c.Args()) 174 | } 175 | 176 | // Get returns the nth argument, or else a blank string 177 | func (a Args) Get(n int) string { 178 | if len(a) > n { 179 | return a[n] 180 | } 181 | return "" 182 | } 183 | 184 | // First returns the first argument, or else a blank string 185 | func (a Args) First() string { 186 | return a.Get(0) 187 | } 188 | 189 | // Tail returns the rest of the arguments (not the first one) 190 | // or else an empty string slice 191 | func (a Args) Tail() []string { 192 | if len(a) >= 2 { 193 | return []string(a)[1:] 194 | } 195 | return []string{} 196 | } 197 | 198 | // Present checks if there are any arguments present 199 | func (a Args) Present() bool { 200 | return len(a) != 0 201 | } 202 | 203 | // Swap swaps arguments at the given indexes 204 | func (a Args) Swap(from, to int) error { 205 | if from >= len(a) || to >= len(a) { 206 | return errors.New("index out of range") 207 | } 208 | a[from], a[to] = a[to], a[from] 209 | return nil 210 | } 211 | 212 | func globalContext(ctx *Context) *Context { 213 | if ctx == nil { 214 | return nil 215 | } 216 | 217 | for { 218 | if ctx.parentContext == nil { 219 | return ctx 220 | } 221 | ctx = ctx.parentContext 222 | } 223 | } 224 | 225 | func lookupGlobalFlagSet(name string, ctx *Context) *flag.FlagSet { 226 | if ctx.parentContext != nil { 227 | ctx = ctx.parentContext 228 | } 229 | for ; ctx != nil; ctx = ctx.parentContext { 230 | if f := ctx.flagSet.Lookup(name); f != nil { 231 | return ctx.flagSet 232 | } 233 | } 234 | return nil 235 | } 236 | 237 | func copyFlag(name string, ff *flag.Flag, set *flag.FlagSet) { 238 | switch ff.Value.(type) { 239 | case *StringSlice: 240 | default: 241 | set.Set(name, ff.Value.String()) 242 | } 243 | } 244 | 245 | func normalizeFlags(flags []Flag, set *flag.FlagSet) error { 246 | visited := make(map[string]bool) 247 | set.Visit(func(f *flag.Flag) { 248 | visited[f.Name] = true 249 | }) 250 | for _, f := range flags { 251 | parts := strings.Split(f.GetName(), ",") 252 | if len(parts) == 1 { 253 | continue 254 | } 255 | var ff *flag.Flag 256 | for _, name := range parts { 257 | name = strings.Trim(name, " ") 258 | if visited[name] { 259 | if ff != nil { 260 | return errors.New("Cannot use two forms of the same flag: " + name + " " + ff.Name) 261 | } 262 | ff = set.Lookup(name) 263 | } 264 | } 265 | if ff == nil { 266 | continue 267 | } 268 | for _, name := range parts { 269 | name = strings.Trim(name, " ") 270 | if !visited[name] { 271 | copyFlag(name, ff, set) 272 | } 273 | } 274 | } 275 | return nil 276 | } 277 | -------------------------------------------------------------------------------- /src/gopkg.in/urfave/cli.v1/errors.go: -------------------------------------------------------------------------------- 1 | package cli 2 | 3 | import ( 4 | "fmt" 5 | "io" 6 | "os" 7 | "strings" 8 | ) 9 | 10 | // OsExiter is the function used when the app exits. If not set defaults to os.Exit. 11 | var OsExiter = os.Exit 12 | 13 | // ErrWriter is used to write errors to the user. This can be anything 14 | // implementing the io.Writer interface and defaults to os.Stderr. 15 | var ErrWriter io.Writer = os.Stderr 16 | 17 | // MultiError is an error that wraps multiple errors. 18 | type MultiError struct { 19 | Errors []error 20 | } 21 | 22 | // NewMultiError creates a new MultiError. Pass in one or more errors. 23 | func NewMultiError(err ...error) MultiError { 24 | return MultiError{Errors: err} 25 | } 26 | 27 | // Error implements the error interface. 28 | func (m MultiError) Error() string { 29 | errs := make([]string, len(m.Errors)) 30 | for i, err := range m.Errors { 31 | errs[i] = err.Error() 32 | } 33 | 34 | return strings.Join(errs, "\n") 35 | } 36 | 37 | type ErrorFormatter interface { 38 | Format(s fmt.State, verb rune) 39 | } 40 | 41 | // ExitCoder is the interface checked by `App` and `Command` for a custom exit 42 | // code 43 | type ExitCoder interface { 44 | error 45 | ExitCode() int 46 | } 47 | 48 | // ExitError fulfills both the builtin `error` interface and `ExitCoder` 49 | type ExitError struct { 50 | exitCode int 51 | message interface{} 52 | } 53 | 54 | // NewExitError makes a new *ExitError 55 | func NewExitError(message interface{}, exitCode int) *ExitError { 56 | return &ExitError{ 57 | exitCode: exitCode, 58 | message: message, 59 | } 60 | } 61 | 62 | // Error returns the string message, fulfilling the interface required by 63 | // `error` 64 | func (ee *ExitError) Error() string { 65 | return fmt.Sprintf("%v", ee.message) 66 | } 67 | 68 | // ExitCode returns the exit code, fulfilling the interface required by 69 | // `ExitCoder` 70 | func (ee *ExitError) ExitCode() int { 71 | return ee.exitCode 72 | } 73 | 74 | // HandleExitCoder checks if the error fulfills the ExitCoder interface, and if 75 | // so prints the error to stderr (if it is non-empty) and calls OsExiter with the 76 | // given exit code. If the given error is a MultiError, then this func is 77 | // called on all members of the Errors slice. 78 | func HandleExitCoder(err error) { 79 | if err == nil { 80 | return 81 | } 82 | 83 | if exitErr, ok := err.(ExitCoder); ok { 84 | if err.Error() != "" { 85 | if _, ok := exitErr.(ErrorFormatter); ok { 86 | fmt.Fprintf(ErrWriter, "%+v\n", err) 87 | } else { 88 | fmt.Fprintln(ErrWriter, err) 89 | } 90 | } 91 | OsExiter(exitErr.ExitCode()) 92 | return 93 | } 94 | 95 | if multiErr, ok := err.(MultiError); ok { 96 | for _, merr := range multiErr.Errors { 97 | HandleExitCoder(merr) 98 | } 99 | return 100 | } 101 | 102 | if err.Error() != "" { 103 | if _, ok := err.(ErrorFormatter); ok { 104 | fmt.Fprintf(ErrWriter, "%+v\n", err) 105 | } else { 106 | fmt.Fprintln(ErrWriter, err) 107 | } 108 | } 109 | OsExiter(1) 110 | } 111 | -------------------------------------------------------------------------------- /src/gopkg.in/urfave/cli.v1/errors_test.go: -------------------------------------------------------------------------------- 1 | package cli 2 | 3 | import ( 4 | "bytes" 5 | "errors" 6 | "fmt" 7 | "testing" 8 | ) 9 | 10 | func TestHandleExitCoder_nil(t *testing.T) { 11 | exitCode := 0 12 | called := false 13 | 14 | OsExiter = func(rc int) { 15 | exitCode = rc 16 | called = true 17 | } 18 | 19 | defer func() { OsExiter = fakeOsExiter }() 20 | 21 | HandleExitCoder(nil) 22 | 23 | expect(t, exitCode, 0) 24 | expect(t, called, false) 25 | } 26 | 27 | func TestHandleExitCoder_ExitCoder(t *testing.T) { 28 | exitCode := 0 29 | called := false 30 | 31 | OsExiter = func(rc int) { 32 | exitCode = rc 33 | called = true 34 | } 35 | 36 | defer func() { OsExiter = fakeOsExiter }() 37 | 38 | HandleExitCoder(NewExitError("galactic perimeter breach", 9)) 39 | 40 | expect(t, exitCode, 9) 41 | expect(t, called, true) 42 | } 43 | 44 | func TestHandleExitCoder_MultiErrorWithExitCoder(t *testing.T) { 45 | exitCode := 0 46 | called := false 47 | 48 | OsExiter = func(rc int) { 49 | exitCode = rc 50 | called = true 51 | } 52 | 53 | defer func() { OsExiter = fakeOsExiter }() 54 | 55 | exitErr := NewExitError("galactic perimeter breach", 9) 56 | err := NewMultiError(errors.New("wowsa"), errors.New("egad"), exitErr) 57 | HandleExitCoder(err) 58 | 59 | expect(t, exitCode, 9) 60 | expect(t, called, true) 61 | } 62 | 63 | func TestHandleExitCoder_ErrorWithMessage(t *testing.T) { 64 | exitCode := 0 65 | called := false 66 | 67 | OsExiter = func(rc int) { 68 | exitCode = rc 69 | called = true 70 | } 71 | ErrWriter = &bytes.Buffer{} 72 | 73 | defer func() { 74 | OsExiter = fakeOsExiter 75 | ErrWriter = fakeErrWriter 76 | }() 77 | 78 | err := errors.New("gourd havens") 79 | HandleExitCoder(err) 80 | 81 | expect(t, exitCode, 1) 82 | expect(t, called, true) 83 | expect(t, ErrWriter.(*bytes.Buffer).String(), "gourd havens\n") 84 | } 85 | 86 | func TestHandleExitCoder_ErrorWithoutMessage(t *testing.T) { 87 | exitCode := 0 88 | called := false 89 | 90 | OsExiter = func(rc int) { 91 | exitCode = rc 92 | called = true 93 | } 94 | ErrWriter = &bytes.Buffer{} 95 | 96 | defer func() { 97 | OsExiter = fakeOsExiter 98 | ErrWriter = fakeErrWriter 99 | }() 100 | 101 | err := errors.New("") 102 | HandleExitCoder(err) 103 | 104 | expect(t, exitCode, 1) 105 | expect(t, called, true) 106 | expect(t, ErrWriter.(*bytes.Buffer).String(), "") 107 | } 108 | 109 | // make a stub to not import pkg/errors 110 | type ErrorWithFormat struct { 111 | error 112 | } 113 | 114 | func NewErrorWithFormat(m string) *ErrorWithFormat { 115 | return &ErrorWithFormat{error: errors.New(m)} 116 | } 117 | 118 | func (f *ErrorWithFormat) Format(s fmt.State, verb rune) { 119 | fmt.Fprintf(s, "This the format: %v", f.error) 120 | } 121 | 122 | func TestHandleExitCoder_ErrorWithFormat(t *testing.T) { 123 | called := false 124 | 125 | OsExiter = func(rc int) { 126 | called = true 127 | } 128 | ErrWriter = &bytes.Buffer{} 129 | 130 | defer func() { 131 | OsExiter = fakeOsExiter 132 | ErrWriter = fakeErrWriter 133 | }() 134 | 135 | err := NewErrorWithFormat("I am formatted") 136 | HandleExitCoder(err) 137 | 138 | expect(t, called, true) 139 | expect(t, ErrWriter.(*bytes.Buffer).String(), "This the format: I am formatted\n") 140 | } 141 | 142 | func TestHandleExitCoder_MultiErrorWithFormat(t *testing.T) { 143 | called := false 144 | 145 | OsExiter = func(rc int) { 146 | called = true 147 | } 148 | ErrWriter = &bytes.Buffer{} 149 | 150 | defer func() { OsExiter = fakeOsExiter }() 151 | 152 | err := NewMultiError(NewErrorWithFormat("err1"), NewErrorWithFormat("err2")) 153 | HandleExitCoder(err) 154 | 155 | expect(t, called, true) 156 | expect(t, ErrWriter.(*bytes.Buffer).String(), "This the format: err1\nThis the format: err2\n") 157 | } 158 | -------------------------------------------------------------------------------- /src/gopkg.in/urfave/cli.v1/flag-types.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "name": "Bool", 4 | "type": "bool", 5 | "value": false, 6 | "context_default": "false", 7 | "parser": "strconv.ParseBool(f.Value.String())" 8 | }, 9 | { 10 | "name": "BoolT", 11 | "type": "bool", 12 | "value": false, 13 | "doctail": " that is true by default", 14 | "context_default": "false", 15 | "parser": "strconv.ParseBool(f.Value.String())" 16 | }, 17 | { 18 | "name": "Duration", 19 | "type": "time.Duration", 20 | "doctail": " (see https://golang.org/pkg/time/#ParseDuration)", 21 | "context_default": "0", 22 | "parser": "time.ParseDuration(f.Value.String())" 23 | }, 24 | { 25 | "name": "Float64", 26 | "type": "float64", 27 | "context_default": "0", 28 | "parser": "strconv.ParseFloat(f.Value.String(), 64)" 29 | }, 30 | { 31 | "name": "Generic", 32 | "type": "Generic", 33 | "dest": false, 34 | "context_default": "nil", 35 | "context_type": "interface{}" 36 | }, 37 | { 38 | "name": "Int64", 39 | "type": "int64", 40 | "context_default": "0", 41 | "parser": "strconv.ParseInt(f.Value.String(), 0, 64)" 42 | }, 43 | { 44 | "name": "Int", 45 | "type": "int", 46 | "context_default": "0", 47 | "parser": "strconv.ParseInt(f.Value.String(), 0, 64)", 48 | "parser_cast": "int(parsed)" 49 | }, 50 | { 51 | "name": "IntSlice", 52 | "type": "*IntSlice", 53 | "dest": false, 54 | "context_default": "nil", 55 | "context_type": "[]int", 56 | "parser": "(f.Value.(*IntSlice)).Value(), error(nil)" 57 | }, 58 | { 59 | "name": "Int64Slice", 60 | "type": "*Int64Slice", 61 | "dest": false, 62 | "context_default": "nil", 63 | "context_type": "[]int64", 64 | "parser": "(f.Value.(*Int64Slice)).Value(), error(nil)" 65 | }, 66 | { 67 | "name": "String", 68 | "type": "string", 69 | "context_default": "\"\"", 70 | "parser": "f.Value.String(), error(nil)" 71 | }, 72 | { 73 | "name": "StringSlice", 74 | "type": "*StringSlice", 75 | "dest": false, 76 | "context_default": "nil", 77 | "context_type": "[]string", 78 | "parser": "(f.Value.(*StringSlice)).Value(), error(nil)" 79 | }, 80 | { 81 | "name": "Uint64", 82 | "type": "uint64", 83 | "context_default": "0", 84 | "parser": "strconv.ParseUint(f.Value.String(), 0, 64)" 85 | }, 86 | { 87 | "name": "Uint", 88 | "type": "uint", 89 | "context_default": "0", 90 | "parser": "strconv.ParseUint(f.Value.String(), 0, 64)", 91 | "parser_cast": "uint(parsed)" 92 | } 93 | ] 94 | -------------------------------------------------------------------------------- /src/gopkg.in/urfave/cli.v1/funcs.go: -------------------------------------------------------------------------------- 1 | package cli 2 | 3 | // BashCompleteFunc is an action to execute when the bash-completion flag is set 4 | type BashCompleteFunc func(*Context) 5 | 6 | // BeforeFunc is an action to execute before any subcommands are run, but after 7 | // the context is ready if a non-nil error is returned, no subcommands are run 8 | type BeforeFunc func(*Context) error 9 | 10 | // AfterFunc is an action to execute after any subcommands are run, but after the 11 | // subcommand has finished it is run even if Action() panics 12 | type AfterFunc func(*Context) error 13 | 14 | // ActionFunc is the action to execute when no subcommands are specified 15 | type ActionFunc func(*Context) error 16 | 17 | // CommandNotFoundFunc is executed if the proper command cannot be found 18 | type CommandNotFoundFunc func(*Context, string) 19 | 20 | // OnUsageErrorFunc is executed if an usage error occurs. This is useful for displaying 21 | // customized usage error messages. This function is able to replace the 22 | // original error messages. If this function is not set, the "Incorrect usage" 23 | // is displayed and the execution is interrupted. 24 | type OnUsageErrorFunc func(context *Context, err error, isSubcommand bool) error 25 | 26 | // FlagStringFunc is used by the help generation to display a flag, which is 27 | // expected to be a single line. 28 | type FlagStringFunc func(Flag) string 29 | -------------------------------------------------------------------------------- /src/gopkg.in/urfave/cli.v1/generate-flag-types: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | """ 3 | The flag types that ship with the cli library have many things in common, and 4 | so we can take advantage of the `go generate` command to create much of the 5 | source code from a list of definitions. These definitions attempt to cover 6 | the parts that vary between flag types, and should evolve as needed. 7 | 8 | An example of the minimum definition needed is: 9 | 10 | { 11 | "name": "SomeType", 12 | "type": "sometype", 13 | "context_default": "nil" 14 | } 15 | 16 | In this example, the code generated for the `cli` package will include a type 17 | named `SomeTypeFlag` that is expected to wrap a value of type `sometype`. 18 | Fetching values by name via `*cli.Context` will default to a value of `nil`. 19 | 20 | A more complete, albeit somewhat redundant, example showing all available 21 | definition keys is: 22 | 23 | { 24 | "name": "VeryMuchType", 25 | "type": "*VeryMuchType", 26 | "value": true, 27 | "dest": false, 28 | "doctail": " which really only wraps a []float64, oh well!", 29 | "context_type": "[]float64", 30 | "context_default": "nil", 31 | "parser": "parseVeryMuchType(f.Value.String())", 32 | "parser_cast": "[]float64(parsed)" 33 | } 34 | 35 | The meaning of each field is as follows: 36 | 37 | name (string) - The type "name", which will be suffixed with 38 | `Flag` when generating the type definition 39 | for `cli` and the wrapper type for `altsrc` 40 | type (string) - The type that the generated `Flag` type for `cli` 41 | is expected to "contain" as its `.Value` member 42 | value (bool) - Should the generated `cli` type have a `Value` 43 | member? 44 | dest (bool) - Should the generated `cli` type support a 45 | destination pointer? 46 | doctail (string) - Additional docs for the `cli` flag type comment 47 | context_type (string) - The literal type used in the `*cli.Context` 48 | reader func signature 49 | context_default (string) - The literal value used as the default by the 50 | `*cli.Context` reader funcs when no value is 51 | present 52 | parser (string) - Literal code used to parse the flag `f`, 53 | expected to have a return signature of 54 | (value, error) 55 | parser_cast (string) - Literal code used to cast the `parsed` value 56 | returned from the `parser` code 57 | """ 58 | 59 | from __future__ import print_function, unicode_literals 60 | 61 | import argparse 62 | import json 63 | import os 64 | import subprocess 65 | import sys 66 | import tempfile 67 | import textwrap 68 | 69 | 70 | class _FancyFormatter(argparse.ArgumentDefaultsHelpFormatter, 71 | argparse.RawDescriptionHelpFormatter): 72 | pass 73 | 74 | 75 | def main(sysargs=sys.argv[:]): 76 | parser = argparse.ArgumentParser( 77 | description='Generate flag type code!', 78 | formatter_class=_FancyFormatter) 79 | parser.add_argument( 80 | 'package', 81 | type=str, default='cli', choices=_WRITEFUNCS.keys(), 82 | help='Package for which flag types will be generated' 83 | ) 84 | parser.add_argument( 85 | '-i', '--in-json', 86 | type=argparse.FileType('r'), 87 | default=sys.stdin, 88 | help='Input JSON file which defines each type to be generated' 89 | ) 90 | parser.add_argument( 91 | '-o', '--out-go', 92 | type=argparse.FileType('w'), 93 | default=sys.stdout, 94 | help='Output file/stream to which generated source will be written' 95 | ) 96 | parser.epilog = __doc__ 97 | 98 | args = parser.parse_args(sysargs[1:]) 99 | _generate_flag_types(_WRITEFUNCS[args.package], args.out_go, args.in_json) 100 | return 0 101 | 102 | 103 | def _generate_flag_types(writefunc, output_go, input_json): 104 | types = json.load(input_json) 105 | 106 | tmp = tempfile.NamedTemporaryFile(suffix='.go', delete=False) 107 | writefunc(tmp, types) 108 | tmp.close() 109 | 110 | new_content = subprocess.check_output( 111 | ['goimports', tmp.name] 112 | ).decode('utf-8') 113 | 114 | print(new_content, file=output_go, end='') 115 | output_go.flush() 116 | os.remove(tmp.name) 117 | 118 | 119 | def _set_typedef_defaults(typedef): 120 | typedef.setdefault('doctail', '') 121 | typedef.setdefault('context_type', typedef['type']) 122 | typedef.setdefault('dest', True) 123 | typedef.setdefault('value', True) 124 | typedef.setdefault('parser', 'f.Value, error(nil)') 125 | typedef.setdefault('parser_cast', 'parsed') 126 | 127 | 128 | def _write_cli_flag_types(outfile, types): 129 | _fwrite(outfile, """\ 130 | package cli 131 | 132 | // WARNING: This file is generated! 133 | 134 | """) 135 | 136 | for typedef in types: 137 | _set_typedef_defaults(typedef) 138 | 139 | _fwrite(outfile, """\ 140 | // {name}Flag is a flag with type {type}{doctail} 141 | type {name}Flag struct {{ 142 | Name string 143 | Usage string 144 | EnvVar string 145 | Hidden bool 146 | """.format(**typedef)) 147 | 148 | if typedef['value']: 149 | _fwrite(outfile, """\ 150 | Value {type} 151 | """.format(**typedef)) 152 | 153 | if typedef['dest']: 154 | _fwrite(outfile, """\ 155 | Destination *{type} 156 | """.format(**typedef)) 157 | 158 | _fwrite(outfile, "\n}\n\n") 159 | 160 | _fwrite(outfile, """\ 161 | // String returns a readable representation of this value 162 | // (for usage defaults) 163 | func (f {name}Flag) String() string {{ 164 | return FlagStringer(f) 165 | }} 166 | 167 | // GetName returns the name of the flag 168 | func (f {name}Flag) GetName() string {{ 169 | return f.Name 170 | }} 171 | 172 | // {name} looks up the value of a local {name}Flag, returns 173 | // {context_default} if not found 174 | func (c *Context) {name}(name string) {context_type} {{ 175 | return lookup{name}(name, c.flagSet) 176 | }} 177 | 178 | // Global{name} looks up the value of a global {name}Flag, returns 179 | // {context_default} if not found 180 | func (c *Context) Global{name}(name string) {context_type} {{ 181 | if fs := lookupGlobalFlagSet(name, c); fs != nil {{ 182 | return lookup{name}(name, fs) 183 | }} 184 | return {context_default} 185 | }} 186 | 187 | func lookup{name}(name string, set *flag.FlagSet) {context_type} {{ 188 | f := set.Lookup(name) 189 | if f != nil {{ 190 | parsed, err := {parser} 191 | if err != nil {{ 192 | return {context_default} 193 | }} 194 | return {parser_cast} 195 | }} 196 | return {context_default} 197 | }} 198 | """.format(**typedef)) 199 | 200 | 201 | def _write_altsrc_flag_types(outfile, types): 202 | _fwrite(outfile, """\ 203 | package altsrc 204 | 205 | import ( 206 | "gopkg.in/urfave/cli.v1" 207 | ) 208 | 209 | // WARNING: This file is generated! 210 | 211 | """) 212 | 213 | for typedef in types: 214 | _set_typedef_defaults(typedef) 215 | 216 | _fwrite(outfile, """\ 217 | // {name}Flag is the flag type that wraps cli.{name}Flag to allow 218 | // for other values to be specified 219 | type {name}Flag struct {{ 220 | cli.{name}Flag 221 | set *flag.FlagSet 222 | }} 223 | 224 | // New{name}Flag creates a new {name}Flag 225 | func New{name}Flag(fl cli.{name}Flag) *{name}Flag {{ 226 | return &{name}Flag{{{name}Flag: fl, set: nil}} 227 | }} 228 | 229 | // Apply saves the flagSet for later usage calls, then calls the 230 | // wrapped {name}Flag.Apply 231 | func (f *{name}Flag) Apply(set *flag.FlagSet) {{ 232 | f.set = set 233 | f.{name}Flag.Apply(set) 234 | }} 235 | 236 | // ApplyWithError saves the flagSet for later usage calls, then calls the 237 | // wrapped {name}Flag.ApplyWithError 238 | func (f *{name}Flag) ApplyWithError(set *flag.FlagSet) error {{ 239 | f.set = set 240 | return f.{name}Flag.ApplyWithError(set) 241 | }} 242 | """.format(**typedef)) 243 | 244 | 245 | def _fwrite(outfile, text): 246 | print(textwrap.dedent(text), end='', file=outfile) 247 | 248 | 249 | _WRITEFUNCS = { 250 | 'cli': _write_cli_flag_types, 251 | 'altsrc': _write_altsrc_flag_types 252 | } 253 | 254 | if __name__ == '__main__': 255 | sys.exit(main()) 256 | -------------------------------------------------------------------------------- /src/gopkg.in/urfave/cli.v1/help.go: -------------------------------------------------------------------------------- 1 | package cli 2 | 3 | import ( 4 | "fmt" 5 | "io" 6 | "os" 7 | "strings" 8 | "text/tabwriter" 9 | "text/template" 10 | ) 11 | 12 | // AppHelpTemplate is the text template for the Default help topic. 13 | // cli.go uses text/template to render templates. You can 14 | // render custom help text by setting this variable. 15 | var AppHelpTemplate = `NAME: 16 | {{.Name}}{{if .Usage}} - {{.Usage}}{{end}} 17 | 18 | USAGE: 19 | {{if .UsageText}}{{.UsageText}}{{else}}{{.HelpName}} {{if .VisibleFlags}}[global options]{{end}}{{if .Commands}} command [command options]{{end}} {{if .ArgsUsage}}{{.ArgsUsage}}{{else}}[arguments...]{{end}}{{end}}{{if .Version}}{{if not .HideVersion}} 20 | 21 | VERSION: 22 | {{.Version}}{{end}}{{end}}{{if .Description}} 23 | 24 | DESCRIPTION: 25 | {{.Description}}{{end}}{{if len .Authors}} 26 | 27 | AUTHOR{{with $length := len .Authors}}{{if ne 1 $length}}S{{end}}{{end}}: 28 | {{range $index, $author := .Authors}}{{if $index}} 29 | {{end}}{{$author}}{{end}}{{end}}{{if .VisibleCommands}} 30 | 31 | COMMANDS:{{range .VisibleCategories}}{{if .Name}} 32 | {{.Name}}:{{end}}{{range .VisibleCommands}} 33 | {{join .Names ", "}}{{"\t"}}{{.Usage}}{{end}}{{end}}{{end}}{{if .VisibleFlags}} 34 | 35 | GLOBAL OPTIONS: 36 | {{range $index, $option := .VisibleFlags}}{{if $index}} 37 | {{end}}{{$option}}{{end}}{{end}}{{if .Copyright}} 38 | 39 | COPYRIGHT: 40 | {{.Copyright}}{{end}} 41 | ` 42 | 43 | // CommandHelpTemplate is the text template for the command help topic. 44 | // cli.go uses text/template to render templates. You can 45 | // render custom help text by setting this variable. 46 | var CommandHelpTemplate = `NAME: 47 | {{.HelpName}} - {{.Usage}} 48 | 49 | USAGE: 50 | {{.HelpName}}{{if .VisibleFlags}} [command options]{{end}} {{if .ArgsUsage}}{{.ArgsUsage}}{{else}}[arguments...]{{end}}{{if .Category}} 51 | 52 | CATEGORY: 53 | {{.Category}}{{end}}{{if .Description}} 54 | 55 | DESCRIPTION: 56 | {{.Description}}{{end}}{{if .VisibleFlags}} 57 | 58 | OPTIONS: 59 | {{range .VisibleFlags}}{{.}} 60 | {{end}}{{end}} 61 | ` 62 | 63 | // SubcommandHelpTemplate is the text template for the subcommand help topic. 64 | // cli.go uses text/template to render templates. You can 65 | // render custom help text by setting this variable. 66 | var SubcommandHelpTemplate = `NAME: 67 | {{.HelpName}} - {{.Usage}} 68 | 69 | USAGE: 70 | {{.HelpName}} command{{if .VisibleFlags}} [command options]{{end}} {{if .ArgsUsage}}{{.ArgsUsage}}{{else}}[arguments...]{{end}} 71 | 72 | COMMANDS:{{range .VisibleCategories}}{{if .Name}} 73 | {{.Name}}:{{end}}{{range .VisibleCommands}} 74 | {{join .Names ", "}}{{"\t"}}{{.Usage}}{{end}} 75 | {{end}}{{if .VisibleFlags}} 76 | OPTIONS: 77 | {{range .VisibleFlags}}{{.}} 78 | {{end}}{{end}} 79 | ` 80 | 81 | var helpCommand = Command{ 82 | Name: "help", 83 | Aliases: []string{"h"}, 84 | Usage: "Shows a list of commands or help for one command", 85 | ArgsUsage: "[command]", 86 | Action: func(c *Context) error { 87 | args := c.Args() 88 | if args.Present() { 89 | return ShowCommandHelp(c, args.First()) 90 | } 91 | 92 | ShowAppHelp(c) 93 | return nil 94 | }, 95 | } 96 | 97 | var helpSubcommand = Command{ 98 | Name: "help", 99 | Aliases: []string{"h"}, 100 | Usage: "Shows a list of commands or help for one command", 101 | ArgsUsage: "[command]", 102 | Action: func(c *Context) error { 103 | args := c.Args() 104 | if args.Present() { 105 | return ShowCommandHelp(c, args.First()) 106 | } 107 | 108 | return ShowSubcommandHelp(c) 109 | }, 110 | } 111 | 112 | // Prints help for the App or Command 113 | type helpPrinter func(w io.Writer, templ string, data interface{}) 114 | 115 | // HelpPrinter is a function that writes the help output. If not set a default 116 | // is used. The function signature is: 117 | // func(w io.Writer, templ string, data interface{}) 118 | var HelpPrinter helpPrinter = printHelp 119 | 120 | // VersionPrinter prints the version for the App 121 | var VersionPrinter = printVersion 122 | 123 | // ShowAppHelp is an action that displays the help. 124 | func ShowAppHelp(c *Context) error { 125 | HelpPrinter(c.App.Writer, AppHelpTemplate, c.App) 126 | return nil 127 | } 128 | 129 | // DefaultAppComplete prints the list of subcommands as the default app completion method 130 | func DefaultAppComplete(c *Context) { 131 | for _, command := range c.App.Commands { 132 | if command.Hidden { 133 | continue 134 | } 135 | for _, name := range command.Names() { 136 | fmt.Fprintln(c.App.Writer, name) 137 | } 138 | } 139 | } 140 | 141 | // ShowCommandHelp prints help for the given command 142 | func ShowCommandHelp(ctx *Context, command string) error { 143 | // show the subcommand help for a command with subcommands 144 | if command == "" { 145 | HelpPrinter(ctx.App.Writer, SubcommandHelpTemplate, ctx.App) 146 | return nil 147 | } 148 | 149 | for _, c := range ctx.App.Commands { 150 | if c.HasName(command) { 151 | HelpPrinter(ctx.App.Writer, CommandHelpTemplate, c) 152 | return nil 153 | } 154 | } 155 | 156 | if ctx.App.CommandNotFound == nil { 157 | return NewExitError(fmt.Sprintf("No help topic for '%v'", command), 3) 158 | } 159 | 160 | ctx.App.CommandNotFound(ctx, command) 161 | return nil 162 | } 163 | 164 | // ShowSubcommandHelp prints help for the given subcommand 165 | func ShowSubcommandHelp(c *Context) error { 166 | return ShowCommandHelp(c, c.Command.Name) 167 | } 168 | 169 | // ShowVersion prints the version number of the App 170 | func ShowVersion(c *Context) { 171 | VersionPrinter(c) 172 | } 173 | 174 | func printVersion(c *Context) { 175 | fmt.Fprintf(c.App.Writer, "%v version %v\n", c.App.Name, c.App.Version) 176 | } 177 | 178 | // ShowCompletions prints the lists of commands within a given context 179 | func ShowCompletions(c *Context) { 180 | a := c.App 181 | if a != nil && a.BashComplete != nil { 182 | a.BashComplete(c) 183 | } 184 | } 185 | 186 | // ShowCommandCompletions prints the custom completions for a given command 187 | func ShowCommandCompletions(ctx *Context, command string) { 188 | c := ctx.App.Command(command) 189 | if c != nil && c.BashComplete != nil { 190 | c.BashComplete(ctx) 191 | } 192 | } 193 | 194 | func printHelp(out io.Writer, templ string, data interface{}) { 195 | funcMap := template.FuncMap{ 196 | "join": strings.Join, 197 | } 198 | 199 | w := tabwriter.NewWriter(out, 1, 8, 2, ' ', 0) 200 | t := template.Must(template.New("help").Funcs(funcMap).Parse(templ)) 201 | err := t.Execute(w, data) 202 | if err != nil { 203 | // If the writer is closed, t.Execute will fail, and there's nothing 204 | // we can do to recover. 205 | if os.Getenv("CLI_TEMPLATE_ERROR_DEBUG") != "" { 206 | fmt.Fprintf(ErrWriter, "CLI TEMPLATE ERROR: %#v\n", err) 207 | } 208 | return 209 | } 210 | w.Flush() 211 | } 212 | 213 | func checkVersion(c *Context) bool { 214 | found := false 215 | if VersionFlag.Name != "" { 216 | eachName(VersionFlag.Name, func(name string) { 217 | if c.GlobalBool(name) || c.Bool(name) { 218 | found = true 219 | } 220 | }) 221 | } 222 | return found 223 | } 224 | 225 | func checkHelp(c *Context) bool { 226 | found := false 227 | if HelpFlag.Name != "" { 228 | eachName(HelpFlag.Name, func(name string) { 229 | if c.GlobalBool(name) || c.Bool(name) { 230 | found = true 231 | } 232 | }) 233 | } 234 | return found 235 | } 236 | 237 | func checkCommandHelp(c *Context, name string) bool { 238 | if c.Bool("h") || c.Bool("help") { 239 | ShowCommandHelp(c, name) 240 | return true 241 | } 242 | 243 | return false 244 | } 245 | 246 | func checkSubcommandHelp(c *Context) bool { 247 | if c.Bool("h") || c.Bool("help") { 248 | ShowSubcommandHelp(c) 249 | return true 250 | } 251 | 252 | return false 253 | } 254 | 255 | func checkShellCompleteFlag(a *App, arguments []string) (bool, []string) { 256 | if !a.EnableBashCompletion { 257 | return false, arguments 258 | } 259 | 260 | pos := len(arguments) - 1 261 | lastArg := arguments[pos] 262 | 263 | if lastArg != "--"+BashCompletionFlag.Name { 264 | return false, arguments 265 | } 266 | 267 | return true, arguments[:pos] 268 | } 269 | 270 | func checkCompletions(c *Context) bool { 271 | if !c.shellComplete { 272 | return false 273 | } 274 | 275 | if args := c.Args(); args.Present() { 276 | name := args.First() 277 | if cmd := c.App.Command(name); cmd != nil { 278 | // let the command handle the completion 279 | return false 280 | } 281 | } 282 | 283 | ShowCompletions(c) 284 | return true 285 | } 286 | 287 | func checkCommandCompletions(c *Context, name string) bool { 288 | if !c.shellComplete { 289 | return false 290 | } 291 | 292 | ShowCommandCompletions(c, name) 293 | return true 294 | } 295 | -------------------------------------------------------------------------------- /src/gopkg.in/urfave/cli.v1/help_test.go: -------------------------------------------------------------------------------- 1 | package cli 2 | 3 | import ( 4 | "bytes" 5 | "flag" 6 | "strings" 7 | "testing" 8 | ) 9 | 10 | func Test_ShowAppHelp_NoAuthor(t *testing.T) { 11 | output := new(bytes.Buffer) 12 | app := NewApp() 13 | app.Writer = output 14 | 15 | c := NewContext(app, nil, nil) 16 | 17 | ShowAppHelp(c) 18 | 19 | if bytes.Index(output.Bytes(), []byte("AUTHOR(S):")) != -1 { 20 | t.Errorf("expected\n%snot to include %s", output.String(), "AUTHOR(S):") 21 | } 22 | } 23 | 24 | func Test_ShowAppHelp_NoVersion(t *testing.T) { 25 | output := new(bytes.Buffer) 26 | app := NewApp() 27 | app.Writer = output 28 | 29 | app.Version = "" 30 | 31 | c := NewContext(app, nil, nil) 32 | 33 | ShowAppHelp(c) 34 | 35 | if bytes.Index(output.Bytes(), []byte("VERSION:")) != -1 { 36 | t.Errorf("expected\n%snot to include %s", output.String(), "VERSION:") 37 | } 38 | } 39 | 40 | func Test_ShowAppHelp_HideVersion(t *testing.T) { 41 | output := new(bytes.Buffer) 42 | app := NewApp() 43 | app.Writer = output 44 | 45 | app.HideVersion = true 46 | 47 | c := NewContext(app, nil, nil) 48 | 49 | ShowAppHelp(c) 50 | 51 | if bytes.Index(output.Bytes(), []byte("VERSION:")) != -1 { 52 | t.Errorf("expected\n%snot to include %s", output.String(), "VERSION:") 53 | } 54 | } 55 | 56 | func Test_Help_Custom_Flags(t *testing.T) { 57 | oldFlag := HelpFlag 58 | defer func() { 59 | HelpFlag = oldFlag 60 | }() 61 | 62 | HelpFlag = BoolFlag{ 63 | Name: "help, x", 64 | Usage: "show help", 65 | } 66 | 67 | app := App{ 68 | Flags: []Flag{ 69 | BoolFlag{Name: "foo, h"}, 70 | }, 71 | Action: func(ctx *Context) error { 72 | if ctx.Bool("h") != true { 73 | t.Errorf("custom help flag not set") 74 | } 75 | return nil 76 | }, 77 | } 78 | output := new(bytes.Buffer) 79 | app.Writer = output 80 | app.Run([]string{"test", "-h"}) 81 | if output.Len() > 0 { 82 | t.Errorf("unexpected output: %s", output.String()) 83 | } 84 | } 85 | 86 | func Test_Version_Custom_Flags(t *testing.T) { 87 | oldFlag := VersionFlag 88 | defer func() { 89 | VersionFlag = oldFlag 90 | }() 91 | 92 | VersionFlag = BoolFlag{ 93 | Name: "version, V", 94 | Usage: "show version", 95 | } 96 | 97 | app := App{ 98 | Flags: []Flag{ 99 | BoolFlag{Name: "foo, v"}, 100 | }, 101 | Action: func(ctx *Context) error { 102 | if ctx.Bool("v") != true { 103 | t.Errorf("custom version flag not set") 104 | } 105 | return nil 106 | }, 107 | } 108 | output := new(bytes.Buffer) 109 | app.Writer = output 110 | app.Run([]string{"test", "-v"}) 111 | if output.Len() > 0 { 112 | t.Errorf("unexpected output: %s", output.String()) 113 | } 114 | } 115 | 116 | func Test_helpCommand_Action_ErrorIfNoTopic(t *testing.T) { 117 | app := NewApp() 118 | 119 | set := flag.NewFlagSet("test", 0) 120 | set.Parse([]string{"foo"}) 121 | 122 | c := NewContext(app, set, nil) 123 | 124 | err := helpCommand.Action.(func(*Context) error)(c) 125 | 126 | if err == nil { 127 | t.Fatalf("expected error from helpCommand.Action(), but got nil") 128 | } 129 | 130 | exitErr, ok := err.(*ExitError) 131 | if !ok { 132 | t.Fatalf("expected ExitError from helpCommand.Action(), but instead got: %v", err.Error()) 133 | } 134 | 135 | if !strings.HasPrefix(exitErr.Error(), "No help topic for") { 136 | t.Fatalf("expected an unknown help topic error, but got: %v", exitErr.Error()) 137 | } 138 | 139 | if exitErr.exitCode != 3 { 140 | t.Fatalf("expected exit value = 3, got %d instead", exitErr.exitCode) 141 | } 142 | } 143 | 144 | func Test_helpCommand_InHelpOutput(t *testing.T) { 145 | app := NewApp() 146 | output := &bytes.Buffer{} 147 | app.Writer = output 148 | app.Run([]string{"test", "--help"}) 149 | 150 | s := output.String() 151 | 152 | if strings.Contains(s, "\nCOMMANDS:\nGLOBAL OPTIONS:\n") { 153 | t.Fatalf("empty COMMANDS section detected: %q", s) 154 | } 155 | 156 | if !strings.Contains(s, "help, h") { 157 | t.Fatalf("missing \"help, h\": %q", s) 158 | } 159 | } 160 | 161 | func Test_helpSubcommand_Action_ErrorIfNoTopic(t *testing.T) { 162 | app := NewApp() 163 | 164 | set := flag.NewFlagSet("test", 0) 165 | set.Parse([]string{"foo"}) 166 | 167 | c := NewContext(app, set, nil) 168 | 169 | err := helpSubcommand.Action.(func(*Context) error)(c) 170 | 171 | if err == nil { 172 | t.Fatalf("expected error from helpCommand.Action(), but got nil") 173 | } 174 | 175 | exitErr, ok := err.(*ExitError) 176 | if !ok { 177 | t.Fatalf("expected ExitError from helpCommand.Action(), but instead got: %v", err.Error()) 178 | } 179 | 180 | if !strings.HasPrefix(exitErr.Error(), "No help topic for") { 181 | t.Fatalf("expected an unknown help topic error, but got: %v", exitErr.Error()) 182 | } 183 | 184 | if exitErr.exitCode != 3 { 185 | t.Fatalf("expected exit value = 3, got %d instead", exitErr.exitCode) 186 | } 187 | } 188 | 189 | func TestShowAppHelp_CommandAliases(t *testing.T) { 190 | app := &App{ 191 | Commands: []Command{ 192 | { 193 | Name: "frobbly", 194 | Aliases: []string{"fr", "frob"}, 195 | Action: func(ctx *Context) error { 196 | return nil 197 | }, 198 | }, 199 | }, 200 | } 201 | 202 | output := &bytes.Buffer{} 203 | app.Writer = output 204 | app.Run([]string{"foo", "--help"}) 205 | 206 | if !strings.Contains(output.String(), "frobbly, fr, frob") { 207 | t.Errorf("expected output to include all command aliases; got: %q", output.String()) 208 | } 209 | } 210 | 211 | func TestShowCommandHelp_CommandAliases(t *testing.T) { 212 | app := &App{ 213 | Commands: []Command{ 214 | { 215 | Name: "frobbly", 216 | Aliases: []string{"fr", "frob", "bork"}, 217 | Action: func(ctx *Context) error { 218 | return nil 219 | }, 220 | }, 221 | }, 222 | } 223 | 224 | output := &bytes.Buffer{} 225 | app.Writer = output 226 | app.Run([]string{"foo", "help", "fr"}) 227 | 228 | if !strings.Contains(output.String(), "frobbly") { 229 | t.Errorf("expected output to include command name; got: %q", output.String()) 230 | } 231 | 232 | if strings.Contains(output.String(), "bork") { 233 | t.Errorf("expected output to exclude command aliases; got: %q", output.String()) 234 | } 235 | } 236 | 237 | func TestShowSubcommandHelp_CommandAliases(t *testing.T) { 238 | app := &App{ 239 | Commands: []Command{ 240 | { 241 | Name: "frobbly", 242 | Aliases: []string{"fr", "frob", "bork"}, 243 | Action: func(ctx *Context) error { 244 | return nil 245 | }, 246 | }, 247 | }, 248 | } 249 | 250 | output := &bytes.Buffer{} 251 | app.Writer = output 252 | app.Run([]string{"foo", "help"}) 253 | 254 | if !strings.Contains(output.String(), "frobbly, fr, frob, bork") { 255 | t.Errorf("expected output to include all command aliases; got: %q", output.String()) 256 | } 257 | } 258 | 259 | func TestShowAppHelp_HiddenCommand(t *testing.T) { 260 | app := &App{ 261 | Commands: []Command{ 262 | { 263 | Name: "frobbly", 264 | Action: func(ctx *Context) error { 265 | return nil 266 | }, 267 | }, 268 | { 269 | Name: "secretfrob", 270 | Hidden: true, 271 | Action: func(ctx *Context) error { 272 | return nil 273 | }, 274 | }, 275 | }, 276 | } 277 | 278 | output := &bytes.Buffer{} 279 | app.Writer = output 280 | app.Run([]string{"app", "--help"}) 281 | 282 | if strings.Contains(output.String(), "secretfrob") { 283 | t.Errorf("expected output to exclude \"secretfrob\"; got: %q", output.String()) 284 | } 285 | 286 | if !strings.Contains(output.String(), "frobbly") { 287 | t.Errorf("expected output to include \"frobbly\"; got: %q", output.String()) 288 | } 289 | } 290 | -------------------------------------------------------------------------------- /src/gopkg.in/urfave/cli.v1/helpers_test.go: -------------------------------------------------------------------------------- 1 | package cli 2 | 3 | import ( 4 | "os" 5 | "reflect" 6 | "runtime" 7 | "strings" 8 | "testing" 9 | ) 10 | 11 | var ( 12 | wd, _ = os.Getwd() 13 | ) 14 | 15 | func expect(t *testing.T, a interface{}, b interface{}) { 16 | _, fn, line, _ := runtime.Caller(1) 17 | fn = strings.Replace(fn, wd+"/", "", -1) 18 | 19 | if !reflect.DeepEqual(a, b) { 20 | t.Errorf("(%s:%d) Expected %v (type %v) - Got %v (type %v)", fn, line, b, reflect.TypeOf(b), a, reflect.TypeOf(a)) 21 | } 22 | } 23 | 24 | func refute(t *testing.T, a interface{}, b interface{}) { 25 | if reflect.DeepEqual(a, b) { 26 | t.Errorf("Did not expect %v (type %v) - Got %v (type %v)", b, reflect.TypeOf(b), a, reflect.TypeOf(a)) 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/gopkg.in/urfave/cli.v1/helpers_unix_test.go: -------------------------------------------------------------------------------- 1 | // +build darwin dragonfly freebsd linux netbsd openbsd solaris 2 | 3 | package cli 4 | 5 | import "os" 6 | 7 | func clearenv() { 8 | os.Clearenv() 9 | } 10 | -------------------------------------------------------------------------------- /src/gopkg.in/urfave/cli.v1/helpers_windows_test.go: -------------------------------------------------------------------------------- 1 | package cli 2 | 3 | import ( 4 | "os" 5 | "syscall" 6 | ) 7 | 8 | // os.Clearenv() doesn't actually unset variables on Windows 9 | // See: https://github.com/golang/go/issues/17902 10 | func clearenv() { 11 | for _, s := range os.Environ() { 12 | for j := 1; j < len(s); j++ { 13 | if s[j] == '=' { 14 | keyp, _ := syscall.UTF16PtrFromString(s[0:j]) 15 | syscall.SetEnvironmentVariable(keyp, nil) 16 | break 17 | } 18 | } 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/gopkg.in/urfave/cli.v1/runtests: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | from __future__ import print_function 3 | 4 | import argparse 5 | import os 6 | import sys 7 | import tempfile 8 | 9 | from subprocess import check_call, check_output 10 | 11 | 12 | PACKAGE_NAME = os.environ.get( 13 | 'CLI_PACKAGE_NAME', 'github.com/urfave/cli' 14 | ) 15 | 16 | 17 | def main(sysargs=sys.argv[:]): 18 | targets = { 19 | 'vet': _vet, 20 | 'test': _test, 21 | 'gfmrun': _gfmrun, 22 | 'toc': _toc, 23 | 'gen': _gen, 24 | } 25 | 26 | parser = argparse.ArgumentParser() 27 | parser.add_argument( 28 | 'target', nargs='?', choices=tuple(targets.keys()), default='test' 29 | ) 30 | args = parser.parse_args(sysargs[1:]) 31 | 32 | targets[args.target]() 33 | return 0 34 | 35 | 36 | def _test(): 37 | if check_output('go version'.split()).split()[2] < 'go1.2': 38 | _run('go test -v .') 39 | return 40 | 41 | coverprofiles = [] 42 | for subpackage in ['', 'altsrc']: 43 | coverprofile = 'cli.coverprofile' 44 | if subpackage != '': 45 | coverprofile = '{}.coverprofile'.format(subpackage) 46 | 47 | coverprofiles.append(coverprofile) 48 | 49 | _run('go test -v'.split() + [ 50 | '-coverprofile={}'.format(coverprofile), 51 | ('{}/{}'.format(PACKAGE_NAME, subpackage)).rstrip('/') 52 | ]) 53 | 54 | combined_name = _combine_coverprofiles(coverprofiles) 55 | _run('go tool cover -func={}'.format(combined_name)) 56 | os.remove(combined_name) 57 | 58 | 59 | def _gfmrun(): 60 | go_version = check_output('go version'.split()).split()[2] 61 | if go_version < 'go1.3': 62 | print('runtests: skip on {}'.format(go_version), file=sys.stderr) 63 | return 64 | _run(['gfmrun', '-c', str(_gfmrun_count()), '-s', 'README.md']) 65 | 66 | 67 | def _vet(): 68 | _run('go vet ./...') 69 | 70 | 71 | def _toc(): 72 | _run('node_modules/.bin/markdown-toc -i README.md') 73 | _run('git diff --exit-code') 74 | 75 | 76 | def _gen(): 77 | go_version = check_output('go version'.split()).split()[2] 78 | if go_version < 'go1.5': 79 | print('runtests: skip on {}'.format(go_version), file=sys.stderr) 80 | return 81 | 82 | _run('go generate ./...') 83 | _run('git diff --exit-code') 84 | 85 | 86 | def _run(command): 87 | if hasattr(command, 'split'): 88 | command = command.split() 89 | print('runtests: {}'.format(' '.join(command)), file=sys.stderr) 90 | check_call(command) 91 | 92 | 93 | def _gfmrun_count(): 94 | with open('README.md') as infile: 95 | lines = infile.read().splitlines() 96 | return len(filter(_is_go_runnable, lines)) 97 | 98 | 99 | def _is_go_runnable(line): 100 | return line.startswith('package main') 101 | 102 | 103 | def _combine_coverprofiles(coverprofiles): 104 | combined = tempfile.NamedTemporaryFile( 105 | suffix='.coverprofile', delete=False 106 | ) 107 | combined.write('mode: set\n') 108 | 109 | for coverprofile in coverprofiles: 110 | with open(coverprofile, 'r') as infile: 111 | for line in infile.readlines(): 112 | if not line.startswith('mode: '): 113 | combined.write(line) 114 | 115 | combined.flush() 116 | name = combined.name 117 | combined.close() 118 | return name 119 | 120 | 121 | if __name__ == '__main__': 122 | sys.exit(main()) 123 | -------------------------------------------------------------------------------- /src/gopkg.in/yaml.v2/LICENSE.libyaml: -------------------------------------------------------------------------------- 1 | The following files were ported to Go from C files of libyaml, and thus 2 | are still covered by their original copyright and license: 3 | 4 | apic.go 5 | emitterc.go 6 | parserc.go 7 | readerc.go 8 | scannerc.go 9 | writerc.go 10 | yamlh.go 11 | yamlprivateh.go 12 | 13 | Copyright (c) 2006 Kirill Simonov 14 | 15 | Permission is hereby granted, free of charge, to any person obtaining a copy of 16 | this software and associated documentation files (the "Software"), to deal in 17 | the Software without restriction, including without limitation the rights to 18 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies 19 | of the Software, and to permit persons to whom the Software is furnished to do 20 | so, subject to the following conditions: 21 | 22 | The above copyright notice and this permission notice shall be included in all 23 | copies or substantial portions of the Software. 24 | 25 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 26 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 27 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 28 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 29 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 30 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 31 | SOFTWARE. 32 | -------------------------------------------------------------------------------- /src/gopkg.in/yaml.v2/README.md: -------------------------------------------------------------------------------- 1 | # YAML support for the Go language 2 | 3 | Introduction 4 | ------------ 5 | 6 | The yaml package enables Go programs to comfortably encode and decode YAML 7 | values. It was developed within [Canonical](https://www.canonical.com) as 8 | part of the [juju](https://juju.ubuntu.com) project, and is based on a 9 | pure Go port of the well-known [libyaml](http://pyyaml.org/wiki/LibYAML) 10 | C library to parse and generate YAML data quickly and reliably. 11 | 12 | Compatibility 13 | ------------- 14 | 15 | The yaml package supports most of YAML 1.1 and 1.2, including support for 16 | anchors, tags, map merging, etc. Multi-document unmarshalling is not yet 17 | implemented, and base-60 floats from YAML 1.1 are purposefully not 18 | supported since they're a poor design and are gone in YAML 1.2. 19 | 20 | Installation and usage 21 | ---------------------- 22 | 23 | The import path for the package is *gopkg.in/yaml.v2*. 24 | 25 | To install it, run: 26 | 27 | go get gopkg.in/yaml.v2 28 | 29 | API documentation 30 | ----------------- 31 | 32 | If opened in a browser, the import path itself leads to the API documentation: 33 | 34 | * [https://gopkg.in/yaml.v2](https://gopkg.in/yaml.v2) 35 | 36 | API stability 37 | ------------- 38 | 39 | The package API for yaml v2 will remain stable as described in [gopkg.in](https://gopkg.in). 40 | 41 | 42 | License 43 | ------- 44 | 45 | The yaml package is licensed under the LGPL with an exception that allows it to be linked statically. Please see the LICENSE file for details. 46 | 47 | 48 | Example 49 | ------- 50 | 51 | ```Go 52 | package main 53 | 54 | import ( 55 | "fmt" 56 | "log" 57 | 58 | "gopkg.in/yaml.v2" 59 | ) 60 | 61 | var data = ` 62 | a: Easy! 63 | b: 64 | c: 2 65 | d: [3, 4] 66 | ` 67 | 68 | type T struct { 69 | A string 70 | B struct { 71 | RenamedC int `yaml:"c"` 72 | D []int `yaml:",flow"` 73 | } 74 | } 75 | 76 | func main() { 77 | t := T{} 78 | 79 | err := yaml.Unmarshal([]byte(data), &t) 80 | if err != nil { 81 | log.Fatalf("error: %v", err) 82 | } 83 | fmt.Printf("--- t:\n%v\n\n", t) 84 | 85 | d, err := yaml.Marshal(&t) 86 | if err != nil { 87 | log.Fatalf("error: %v", err) 88 | } 89 | fmt.Printf("--- t dump:\n%s\n\n", string(d)) 90 | 91 | m := make(map[interface{}]interface{}) 92 | 93 | err = yaml.Unmarshal([]byte(data), &m) 94 | if err != nil { 95 | log.Fatalf("error: %v", err) 96 | } 97 | fmt.Printf("--- m:\n%v\n\n", m) 98 | 99 | d, err = yaml.Marshal(&m) 100 | if err != nil { 101 | log.Fatalf("error: %v", err) 102 | } 103 | fmt.Printf("--- m dump:\n%s\n\n", string(d)) 104 | } 105 | ``` 106 | 107 | This example will generate the following output: 108 | 109 | ``` 110 | --- t: 111 | {Easy! {2 [3 4]}} 112 | 113 | --- t dump: 114 | a: Easy! 115 | b: 116 | c: 2 117 | d: [3, 4] 118 | 119 | 120 | --- m: 121 | map[a:Easy! b:map[c:2 d:[3 4]]] 122 | 123 | --- m dump: 124 | a: Easy! 125 | b: 126 | c: 2 127 | d: 128 | - 3 129 | - 4 130 | ``` 131 | 132 | -------------------------------------------------------------------------------- /src/gopkg.in/yaml.v2/encode.go: -------------------------------------------------------------------------------- 1 | package yaml 2 | 3 | import ( 4 | "encoding" 5 | "fmt" 6 | "reflect" 7 | "regexp" 8 | "sort" 9 | "strconv" 10 | "strings" 11 | "time" 12 | ) 13 | 14 | type encoder struct { 15 | emitter yaml_emitter_t 16 | event yaml_event_t 17 | out []byte 18 | flow bool 19 | } 20 | 21 | func newEncoder() (e *encoder) { 22 | e = &encoder{} 23 | e.must(yaml_emitter_initialize(&e.emitter)) 24 | yaml_emitter_set_output_string(&e.emitter, &e.out) 25 | yaml_emitter_set_unicode(&e.emitter, true) 26 | e.must(yaml_stream_start_event_initialize(&e.event, yaml_UTF8_ENCODING)) 27 | e.emit() 28 | e.must(yaml_document_start_event_initialize(&e.event, nil, nil, true)) 29 | e.emit() 30 | return e 31 | } 32 | 33 | func (e *encoder) finish() { 34 | e.must(yaml_document_end_event_initialize(&e.event, true)) 35 | e.emit() 36 | e.emitter.open_ended = false 37 | e.must(yaml_stream_end_event_initialize(&e.event)) 38 | e.emit() 39 | } 40 | 41 | func (e *encoder) destroy() { 42 | yaml_emitter_delete(&e.emitter) 43 | } 44 | 45 | func (e *encoder) emit() { 46 | // This will internally delete the e.event value. 47 | if !yaml_emitter_emit(&e.emitter, &e.event) && e.event.typ != yaml_DOCUMENT_END_EVENT && e.event.typ != yaml_STREAM_END_EVENT { 48 | e.must(false) 49 | } 50 | } 51 | 52 | func (e *encoder) must(ok bool) { 53 | if !ok { 54 | msg := e.emitter.problem 55 | if msg == "" { 56 | msg = "unknown problem generating YAML content" 57 | } 58 | failf("%s", msg) 59 | } 60 | } 61 | 62 | func (e *encoder) marshal(tag string, in reflect.Value) { 63 | if !in.IsValid() { 64 | e.nilv() 65 | return 66 | } 67 | iface := in.Interface() 68 | if m, ok := iface.(Marshaler); ok { 69 | v, err := m.MarshalYAML() 70 | if err != nil { 71 | fail(err) 72 | } 73 | if v == nil { 74 | e.nilv() 75 | return 76 | } 77 | in = reflect.ValueOf(v) 78 | } else if m, ok := iface.(encoding.TextMarshaler); ok { 79 | text, err := m.MarshalText() 80 | if err != nil { 81 | fail(err) 82 | } 83 | in = reflect.ValueOf(string(text)) 84 | } 85 | switch in.Kind() { 86 | case reflect.Interface: 87 | if in.IsNil() { 88 | e.nilv() 89 | } else { 90 | e.marshal(tag, in.Elem()) 91 | } 92 | case reflect.Map: 93 | e.mapv(tag, in) 94 | case reflect.Ptr: 95 | if in.IsNil() { 96 | e.nilv() 97 | } else { 98 | e.marshal(tag, in.Elem()) 99 | } 100 | case reflect.Struct: 101 | e.structv(tag, in) 102 | case reflect.Slice: 103 | if in.Type().Elem() == mapItemType { 104 | e.itemsv(tag, in) 105 | } else { 106 | e.slicev(tag, in) 107 | } 108 | case reflect.String: 109 | e.stringv(tag, in) 110 | case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: 111 | if in.Type() == durationType { 112 | e.stringv(tag, reflect.ValueOf(iface.(time.Duration).String())) 113 | } else { 114 | e.intv(tag, in) 115 | } 116 | case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: 117 | e.uintv(tag, in) 118 | case reflect.Float32, reflect.Float64: 119 | e.floatv(tag, in) 120 | case reflect.Bool: 121 | e.boolv(tag, in) 122 | default: 123 | panic("cannot marshal type: " + in.Type().String()) 124 | } 125 | } 126 | 127 | func (e *encoder) mapv(tag string, in reflect.Value) { 128 | e.mappingv(tag, func() { 129 | keys := keyList(in.MapKeys()) 130 | sort.Sort(keys) 131 | for _, k := range keys { 132 | e.marshal("", k) 133 | e.marshal("", in.MapIndex(k)) 134 | } 135 | }) 136 | } 137 | 138 | func (e *encoder) itemsv(tag string, in reflect.Value) { 139 | e.mappingv(tag, func() { 140 | slice := in.Convert(reflect.TypeOf([]MapItem{})).Interface().([]MapItem) 141 | for _, item := range slice { 142 | e.marshal("", reflect.ValueOf(item.Key)) 143 | e.marshal("", reflect.ValueOf(item.Value)) 144 | } 145 | }) 146 | } 147 | 148 | func (e *encoder) structv(tag string, in reflect.Value) { 149 | sinfo, err := getStructInfo(in.Type()) 150 | if err != nil { 151 | panic(err) 152 | } 153 | e.mappingv(tag, func() { 154 | for _, info := range sinfo.FieldsList { 155 | var value reflect.Value 156 | if info.Inline == nil { 157 | value = in.Field(info.Num) 158 | } else { 159 | value = in.FieldByIndex(info.Inline) 160 | } 161 | if info.OmitEmpty && isZero(value) { 162 | continue 163 | } 164 | e.marshal("", reflect.ValueOf(info.Key)) 165 | e.flow = info.Flow 166 | e.marshal("", value) 167 | } 168 | if sinfo.InlineMap >= 0 { 169 | m := in.Field(sinfo.InlineMap) 170 | if m.Len() > 0 { 171 | e.flow = false 172 | keys := keyList(m.MapKeys()) 173 | sort.Sort(keys) 174 | for _, k := range keys { 175 | if _, found := sinfo.FieldsMap[k.String()]; found { 176 | panic(fmt.Sprintf("Can't have key %q in inlined map; conflicts with struct field", k.String())) 177 | } 178 | e.marshal("", k) 179 | e.flow = false 180 | e.marshal("", m.MapIndex(k)) 181 | } 182 | } 183 | } 184 | }) 185 | } 186 | 187 | func (e *encoder) mappingv(tag string, f func()) { 188 | implicit := tag == "" 189 | style := yaml_BLOCK_MAPPING_STYLE 190 | if e.flow { 191 | e.flow = false 192 | style = yaml_FLOW_MAPPING_STYLE 193 | } 194 | e.must(yaml_mapping_start_event_initialize(&e.event, nil, []byte(tag), implicit, style)) 195 | e.emit() 196 | f() 197 | e.must(yaml_mapping_end_event_initialize(&e.event)) 198 | e.emit() 199 | } 200 | 201 | func (e *encoder) slicev(tag string, in reflect.Value) { 202 | implicit := tag == "" 203 | style := yaml_BLOCK_SEQUENCE_STYLE 204 | if e.flow { 205 | e.flow = false 206 | style = yaml_FLOW_SEQUENCE_STYLE 207 | } 208 | e.must(yaml_sequence_start_event_initialize(&e.event, nil, []byte(tag), implicit, style)) 209 | e.emit() 210 | n := in.Len() 211 | for i := 0; i < n; i++ { 212 | e.marshal("", in.Index(i)) 213 | } 214 | e.must(yaml_sequence_end_event_initialize(&e.event)) 215 | e.emit() 216 | } 217 | 218 | // isBase60 returns whether s is in base 60 notation as defined in YAML 1.1. 219 | // 220 | // The base 60 float notation in YAML 1.1 is a terrible idea and is unsupported 221 | // in YAML 1.2 and by this package, but these should be marshalled quoted for 222 | // the time being for compatibility with other parsers. 223 | func isBase60Float(s string) (result bool) { 224 | // Fast path. 225 | if s == "" { 226 | return false 227 | } 228 | c := s[0] 229 | if !(c == '+' || c == '-' || c >= '0' && c <= '9') || strings.IndexByte(s, ':') < 0 { 230 | return false 231 | } 232 | // Do the full match. 233 | return base60float.MatchString(s) 234 | } 235 | 236 | // From http://yaml.org/type/float.html, except the regular expression there 237 | // is bogus. In practice parsers do not enforce the "\.[0-9_]*" suffix. 238 | var base60float = regexp.MustCompile(`^[-+]?[0-9][0-9_]*(?::[0-5]?[0-9])+(?:\.[0-9_]*)?$`) 239 | 240 | func (e *encoder) stringv(tag string, in reflect.Value) { 241 | var style yaml_scalar_style_t 242 | s := in.String() 243 | rtag, rs := resolve("", s) 244 | if rtag == yaml_BINARY_TAG { 245 | if tag == "" || tag == yaml_STR_TAG { 246 | tag = rtag 247 | s = rs.(string) 248 | } else if tag == yaml_BINARY_TAG { 249 | failf("explicitly tagged !!binary data must be base64-encoded") 250 | } else { 251 | failf("cannot marshal invalid UTF-8 data as %s", shortTag(tag)) 252 | } 253 | } 254 | if tag == "" && (rtag != yaml_STR_TAG || isBase60Float(s)) { 255 | style = yaml_DOUBLE_QUOTED_SCALAR_STYLE 256 | } else if strings.Contains(s, "\n") { 257 | style = yaml_LITERAL_SCALAR_STYLE 258 | } else { 259 | style = yaml_PLAIN_SCALAR_STYLE 260 | } 261 | e.emitScalar(s, "", tag, style) 262 | } 263 | 264 | func (e *encoder) boolv(tag string, in reflect.Value) { 265 | var s string 266 | if in.Bool() { 267 | s = "true" 268 | } else { 269 | s = "false" 270 | } 271 | e.emitScalar(s, "", tag, yaml_PLAIN_SCALAR_STYLE) 272 | } 273 | 274 | func (e *encoder) intv(tag string, in reflect.Value) { 275 | s := strconv.FormatInt(in.Int(), 10) 276 | e.emitScalar(s, "", tag, yaml_PLAIN_SCALAR_STYLE) 277 | } 278 | 279 | func (e *encoder) uintv(tag string, in reflect.Value) { 280 | s := strconv.FormatUint(in.Uint(), 10) 281 | e.emitScalar(s, "", tag, yaml_PLAIN_SCALAR_STYLE) 282 | } 283 | 284 | func (e *encoder) floatv(tag string, in reflect.Value) { 285 | // FIXME: Handle 64 bits here. 286 | s := strconv.FormatFloat(float64(in.Float()), 'g', -1, 32) 287 | switch s { 288 | case "+Inf": 289 | s = ".inf" 290 | case "-Inf": 291 | s = "-.inf" 292 | case "NaN": 293 | s = ".nan" 294 | } 295 | e.emitScalar(s, "", tag, yaml_PLAIN_SCALAR_STYLE) 296 | } 297 | 298 | func (e *encoder) nilv() { 299 | e.emitScalar("null", "", "", yaml_PLAIN_SCALAR_STYLE) 300 | } 301 | 302 | func (e *encoder) emitScalar(value, anchor, tag string, style yaml_scalar_style_t) { 303 | implicit := tag == "" 304 | e.must(yaml_scalar_event_initialize(&e.event, []byte(anchor), []byte(tag), []byte(value), implicit, implicit, style)) 305 | e.emit() 306 | } 307 | -------------------------------------------------------------------------------- /src/gopkg.in/yaml.v2/resolve.go: -------------------------------------------------------------------------------- 1 | package yaml 2 | 3 | import ( 4 | "encoding/base64" 5 | "math" 6 | "strconv" 7 | "strings" 8 | "unicode/utf8" 9 | ) 10 | 11 | type resolveMapItem struct { 12 | value interface{} 13 | tag string 14 | } 15 | 16 | var resolveTable = make([]byte, 256) 17 | var resolveMap = make(map[string]resolveMapItem) 18 | 19 | func init() { 20 | t := resolveTable 21 | t[int('+')] = 'S' // Sign 22 | t[int('-')] = 'S' 23 | for _, c := range "0123456789" { 24 | t[int(c)] = 'D' // Digit 25 | } 26 | for _, c := range "yYnNtTfFoO~" { 27 | t[int(c)] = 'M' // In map 28 | } 29 | t[int('.')] = '.' // Float (potentially in map) 30 | 31 | var resolveMapList = []struct { 32 | v interface{} 33 | tag string 34 | l []string 35 | }{ 36 | {true, yaml_BOOL_TAG, []string{"y", "Y", "yes", "Yes", "YES"}}, 37 | {true, yaml_BOOL_TAG, []string{"true", "True", "TRUE"}}, 38 | {true, yaml_BOOL_TAG, []string{"on", "On", "ON"}}, 39 | {false, yaml_BOOL_TAG, []string{"n", "N", "no", "No", "NO"}}, 40 | {false, yaml_BOOL_TAG, []string{"false", "False", "FALSE"}}, 41 | {false, yaml_BOOL_TAG, []string{"off", "Off", "OFF"}}, 42 | {nil, yaml_NULL_TAG, []string{"", "~", "null", "Null", "NULL"}}, 43 | {math.NaN(), yaml_FLOAT_TAG, []string{".nan", ".NaN", ".NAN"}}, 44 | {math.Inf(+1), yaml_FLOAT_TAG, []string{".inf", ".Inf", ".INF"}}, 45 | {math.Inf(+1), yaml_FLOAT_TAG, []string{"+.inf", "+.Inf", "+.INF"}}, 46 | {math.Inf(-1), yaml_FLOAT_TAG, []string{"-.inf", "-.Inf", "-.INF"}}, 47 | {"<<", yaml_MERGE_TAG, []string{"<<"}}, 48 | } 49 | 50 | m := resolveMap 51 | for _, item := range resolveMapList { 52 | for _, s := range item.l { 53 | m[s] = resolveMapItem{item.v, item.tag} 54 | } 55 | } 56 | } 57 | 58 | const longTagPrefix = "tag:yaml.org,2002:" 59 | 60 | func shortTag(tag string) string { 61 | // TODO This can easily be made faster and produce less garbage. 62 | if strings.HasPrefix(tag, longTagPrefix) { 63 | return "!!" + tag[len(longTagPrefix):] 64 | } 65 | return tag 66 | } 67 | 68 | func longTag(tag string) string { 69 | if strings.HasPrefix(tag, "!!") { 70 | return longTagPrefix + tag[2:] 71 | } 72 | return tag 73 | } 74 | 75 | func resolvableTag(tag string) bool { 76 | switch tag { 77 | case "", yaml_STR_TAG, yaml_BOOL_TAG, yaml_INT_TAG, yaml_FLOAT_TAG, yaml_NULL_TAG: 78 | return true 79 | } 80 | return false 81 | } 82 | 83 | func resolve(tag string, in string) (rtag string, out interface{}) { 84 | if !resolvableTag(tag) { 85 | return tag, in 86 | } 87 | 88 | defer func() { 89 | switch tag { 90 | case "", rtag, yaml_STR_TAG, yaml_BINARY_TAG: 91 | return 92 | } 93 | failf("cannot decode %s `%s` as a %s", shortTag(rtag), in, shortTag(tag)) 94 | }() 95 | 96 | // Any data is accepted as a !!str or !!binary. 97 | // Otherwise, the prefix is enough of a hint about what it might be. 98 | hint := byte('N') 99 | if in != "" { 100 | hint = resolveTable[in[0]] 101 | } 102 | if hint != 0 && tag != yaml_STR_TAG && tag != yaml_BINARY_TAG { 103 | // Handle things we can lookup in a map. 104 | if item, ok := resolveMap[in]; ok { 105 | return item.tag, item.value 106 | } 107 | 108 | // Base 60 floats are a bad idea, were dropped in YAML 1.2, and 109 | // are purposefully unsupported here. They're still quoted on 110 | // the way out for compatibility with other parser, though. 111 | 112 | switch hint { 113 | case 'M': 114 | // We've already checked the map above. 115 | 116 | case '.': 117 | // Not in the map, so maybe a normal float. 118 | floatv, err := strconv.ParseFloat(in, 64) 119 | if err == nil { 120 | return yaml_FLOAT_TAG, floatv 121 | } 122 | 123 | case 'D', 'S': 124 | // Int, float, or timestamp. 125 | plain := strings.Replace(in, "_", "", -1) 126 | intv, err := strconv.ParseInt(plain, 0, 64) 127 | if err == nil { 128 | if intv == int64(int(intv)) { 129 | return yaml_INT_TAG, int(intv) 130 | } else { 131 | return yaml_INT_TAG, intv 132 | } 133 | } 134 | uintv, err := strconv.ParseUint(plain, 0, 64) 135 | if err == nil { 136 | return yaml_INT_TAG, uintv 137 | } 138 | floatv, err := strconv.ParseFloat(plain, 64) 139 | if err == nil { 140 | return yaml_FLOAT_TAG, floatv 141 | } 142 | if strings.HasPrefix(plain, "0b") { 143 | intv, err := strconv.ParseInt(plain[2:], 2, 64) 144 | if err == nil { 145 | if intv == int64(int(intv)) { 146 | return yaml_INT_TAG, int(intv) 147 | } else { 148 | return yaml_INT_TAG, intv 149 | } 150 | } 151 | uintv, err := strconv.ParseUint(plain[2:], 2, 64) 152 | if err == nil { 153 | return yaml_INT_TAG, uintv 154 | } 155 | } else if strings.HasPrefix(plain, "-0b") { 156 | intv, err := strconv.ParseInt(plain[3:], 2, 64) 157 | if err == nil { 158 | if intv == int64(int(intv)) { 159 | return yaml_INT_TAG, -int(intv) 160 | } else { 161 | return yaml_INT_TAG, -intv 162 | } 163 | } 164 | } 165 | // XXX Handle timestamps here. 166 | 167 | default: 168 | panic("resolveTable item not yet handled: " + string(rune(hint)) + " (with " + in + ")") 169 | } 170 | } 171 | if tag == yaml_BINARY_TAG { 172 | return yaml_BINARY_TAG, in 173 | } 174 | if utf8.ValidString(in) { 175 | return yaml_STR_TAG, in 176 | } 177 | return yaml_BINARY_TAG, encodeBase64(in) 178 | } 179 | 180 | // encodeBase64 encodes s as base64 that is broken up into multiple lines 181 | // as appropriate for the resulting length. 182 | func encodeBase64(s string) string { 183 | const lineLen = 70 184 | encLen := base64.StdEncoding.EncodedLen(len(s)) 185 | lines := encLen/lineLen + 1 186 | buf := make([]byte, encLen*2+lines) 187 | in := buf[0:encLen] 188 | out := buf[encLen:] 189 | base64.StdEncoding.Encode(in, []byte(s)) 190 | k := 0 191 | for i := 0; i < len(in); i += lineLen { 192 | j := i + lineLen 193 | if j > len(in) { 194 | j = len(in) 195 | } 196 | k += copy(out[k:], in[i:j]) 197 | if lines > 1 { 198 | out[k] = '\n' 199 | k++ 200 | } 201 | } 202 | return string(out[:k]) 203 | } 204 | -------------------------------------------------------------------------------- /src/gopkg.in/yaml.v2/sorter.go: -------------------------------------------------------------------------------- 1 | package yaml 2 | 3 | import ( 4 | "reflect" 5 | "unicode" 6 | ) 7 | 8 | type keyList []reflect.Value 9 | 10 | func (l keyList) Len() int { return len(l) } 11 | func (l keyList) Swap(i, j int) { l[i], l[j] = l[j], l[i] } 12 | func (l keyList) Less(i, j int) bool { 13 | a := l[i] 14 | b := l[j] 15 | ak := a.Kind() 16 | bk := b.Kind() 17 | for (ak == reflect.Interface || ak == reflect.Ptr) && !a.IsNil() { 18 | a = a.Elem() 19 | ak = a.Kind() 20 | } 21 | for (bk == reflect.Interface || bk == reflect.Ptr) && !b.IsNil() { 22 | b = b.Elem() 23 | bk = b.Kind() 24 | } 25 | af, aok := keyFloat(a) 26 | bf, bok := keyFloat(b) 27 | if aok && bok { 28 | if af != bf { 29 | return af < bf 30 | } 31 | if ak != bk { 32 | return ak < bk 33 | } 34 | return numLess(a, b) 35 | } 36 | if ak != reflect.String || bk != reflect.String { 37 | return ak < bk 38 | } 39 | ar, br := []rune(a.String()), []rune(b.String()) 40 | for i := 0; i < len(ar) && i < len(br); i++ { 41 | if ar[i] == br[i] { 42 | continue 43 | } 44 | al := unicode.IsLetter(ar[i]) 45 | bl := unicode.IsLetter(br[i]) 46 | if al && bl { 47 | return ar[i] < br[i] 48 | } 49 | if al || bl { 50 | return bl 51 | } 52 | var ai, bi int 53 | var an, bn int64 54 | for ai = i; ai < len(ar) && unicode.IsDigit(ar[ai]); ai++ { 55 | an = an*10 + int64(ar[ai]-'0') 56 | } 57 | for bi = i; bi < len(br) && unicode.IsDigit(br[bi]); bi++ { 58 | bn = bn*10 + int64(br[bi]-'0') 59 | } 60 | if an != bn { 61 | return an < bn 62 | } 63 | if ai != bi { 64 | return ai < bi 65 | } 66 | return ar[i] < br[i] 67 | } 68 | return len(ar) < len(br) 69 | } 70 | 71 | // keyFloat returns a float value for v if it is a number/bool 72 | // and whether it is a number/bool or not. 73 | func keyFloat(v reflect.Value) (f float64, ok bool) { 74 | switch v.Kind() { 75 | case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: 76 | return float64(v.Int()), true 77 | case reflect.Float32, reflect.Float64: 78 | return v.Float(), true 79 | case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: 80 | return float64(v.Uint()), true 81 | case reflect.Bool: 82 | if v.Bool() { 83 | return 1, true 84 | } 85 | return 0, true 86 | } 87 | return 0, false 88 | } 89 | 90 | // numLess returns whether a < b. 91 | // a and b must necessarily have the same kind. 92 | func numLess(a, b reflect.Value) bool { 93 | switch a.Kind() { 94 | case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: 95 | return a.Int() < b.Int() 96 | case reflect.Float32, reflect.Float64: 97 | return a.Float() < b.Float() 98 | case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: 99 | return a.Uint() < b.Uint() 100 | case reflect.Bool: 101 | return !a.Bool() && b.Bool() 102 | } 103 | panic("not a number") 104 | } 105 | -------------------------------------------------------------------------------- /src/gopkg.in/yaml.v2/suite_test.go: -------------------------------------------------------------------------------- 1 | package yaml_test 2 | 3 | import ( 4 | . "gopkg.in/check.v1" 5 | "testing" 6 | ) 7 | 8 | func Test(t *testing.T) { TestingT(t) } 9 | 10 | type S struct{} 11 | 12 | var _ = Suite(&S{}) 13 | -------------------------------------------------------------------------------- /src/gopkg.in/yaml.v2/writerc.go: -------------------------------------------------------------------------------- 1 | package yaml 2 | 3 | // Set the writer error and return false. 4 | func yaml_emitter_set_writer_error(emitter *yaml_emitter_t, problem string) bool { 5 | emitter.error = yaml_WRITER_ERROR 6 | emitter.problem = problem 7 | return false 8 | } 9 | 10 | // Flush the output buffer. 11 | func yaml_emitter_flush(emitter *yaml_emitter_t) bool { 12 | if emitter.write_handler == nil { 13 | panic("write handler not set") 14 | } 15 | 16 | // Check if the buffer is empty. 17 | if emitter.buffer_pos == 0 { 18 | return true 19 | } 20 | 21 | // If the output encoding is UTF-8, we don't need to recode the buffer. 22 | if emitter.encoding == yaml_UTF8_ENCODING { 23 | if err := emitter.write_handler(emitter, emitter.buffer[:emitter.buffer_pos]); err != nil { 24 | return yaml_emitter_set_writer_error(emitter, "write error: "+err.Error()) 25 | } 26 | emitter.buffer_pos = 0 27 | return true 28 | } 29 | 30 | // Recode the buffer into the raw buffer. 31 | var low, high int 32 | if emitter.encoding == yaml_UTF16LE_ENCODING { 33 | low, high = 0, 1 34 | } else { 35 | high, low = 1, 0 36 | } 37 | 38 | pos := 0 39 | for pos < emitter.buffer_pos { 40 | // See the "reader.c" code for more details on UTF-8 encoding. Note 41 | // that we assume that the buffer contains a valid UTF-8 sequence. 42 | 43 | // Read the next UTF-8 character. 44 | octet := emitter.buffer[pos] 45 | 46 | var w int 47 | var value rune 48 | switch { 49 | case octet&0x80 == 0x00: 50 | w, value = 1, rune(octet&0x7F) 51 | case octet&0xE0 == 0xC0: 52 | w, value = 2, rune(octet&0x1F) 53 | case octet&0xF0 == 0xE0: 54 | w, value = 3, rune(octet&0x0F) 55 | case octet&0xF8 == 0xF0: 56 | w, value = 4, rune(octet&0x07) 57 | } 58 | for k := 1; k < w; k++ { 59 | octet = emitter.buffer[pos+k] 60 | value = (value << 6) + (rune(octet) & 0x3F) 61 | } 62 | pos += w 63 | 64 | // Write the character. 65 | if value < 0x10000 { 66 | var b [2]byte 67 | b[high] = byte(value >> 8) 68 | b[low] = byte(value & 0xFF) 69 | emitter.raw_buffer = append(emitter.raw_buffer, b[0], b[1]) 70 | } else { 71 | // Write the character using a surrogate pair (check "reader.c"). 72 | var b [4]byte 73 | value -= 0x10000 74 | b[high] = byte(0xD8 + (value >> 18)) 75 | b[low] = byte((value >> 10) & 0xFF) 76 | b[high+2] = byte(0xDC + ((value >> 8) & 0xFF)) 77 | b[low+2] = byte(value & 0xFF) 78 | emitter.raw_buffer = append(emitter.raw_buffer, b[0], b[1], b[2], b[3]) 79 | } 80 | } 81 | 82 | // Write the raw buffer. 83 | if err := emitter.write_handler(emitter, emitter.raw_buffer); err != nil { 84 | return yaml_emitter_set_writer_error(emitter, "write error: "+err.Error()) 85 | } 86 | emitter.buffer_pos = 0 87 | emitter.raw_buffer = emitter.raw_buffer[:0] 88 | return true 89 | } 90 | -------------------------------------------------------------------------------- /src/gopkg.in/yaml.v2/yamlprivateh.go: -------------------------------------------------------------------------------- 1 | package yaml 2 | 3 | const ( 4 | // The size of the input raw buffer. 5 | input_raw_buffer_size = 512 6 | 7 | // The size of the input buffer. 8 | // It should be possible to decode the whole raw buffer. 9 | input_buffer_size = input_raw_buffer_size * 3 10 | 11 | // The size of the output buffer. 12 | output_buffer_size = 128 13 | 14 | // The size of the output raw buffer. 15 | // It should be possible to encode the whole output buffer. 16 | output_raw_buffer_size = (output_buffer_size*2 + 2) 17 | 18 | // The size of other stacks and queues. 19 | initial_stack_size = 16 20 | initial_queue_size = 16 21 | initial_string_size = 16 22 | ) 23 | 24 | // Check if the character at the specified position is an alphabetical 25 | // character, a digit, '_', or '-'. 26 | func is_alpha(b []byte, i int) bool { 27 | return b[i] >= '0' && b[i] <= '9' || b[i] >= 'A' && b[i] <= 'Z' || b[i] >= 'a' && b[i] <= 'z' || b[i] == '_' || b[i] == '-' 28 | } 29 | 30 | // Check if the character at the specified position is a digit. 31 | func is_digit(b []byte, i int) bool { 32 | return b[i] >= '0' && b[i] <= '9' 33 | } 34 | 35 | // Get the value of a digit. 36 | func as_digit(b []byte, i int) int { 37 | return int(b[i]) - '0' 38 | } 39 | 40 | // Check if the character at the specified position is a hex-digit. 41 | func is_hex(b []byte, i int) bool { 42 | return b[i] >= '0' && b[i] <= '9' || b[i] >= 'A' && b[i] <= 'F' || b[i] >= 'a' && b[i] <= 'f' 43 | } 44 | 45 | // Get the value of a hex-digit. 46 | func as_hex(b []byte, i int) int { 47 | bi := b[i] 48 | if bi >= 'A' && bi <= 'F' { 49 | return int(bi) - 'A' + 10 50 | } 51 | if bi >= 'a' && bi <= 'f' { 52 | return int(bi) - 'a' + 10 53 | } 54 | return int(bi) - '0' 55 | } 56 | 57 | // Check if the character is ASCII. 58 | func is_ascii(b []byte, i int) bool { 59 | return b[i] <= 0x7F 60 | } 61 | 62 | // Check if the character at the start of the buffer can be printed unescaped. 63 | func is_printable(b []byte, i int) bool { 64 | return ((b[i] == 0x0A) || // . == #x0A 65 | (b[i] >= 0x20 && b[i] <= 0x7E) || // #x20 <= . <= #x7E 66 | (b[i] == 0xC2 && b[i+1] >= 0xA0) || // #0xA0 <= . <= #xD7FF 67 | (b[i] > 0xC2 && b[i] < 0xED) || 68 | (b[i] == 0xED && b[i+1] < 0xA0) || 69 | (b[i] == 0xEE) || 70 | (b[i] == 0xEF && // #xE000 <= . <= #xFFFD 71 | !(b[i+1] == 0xBB && b[i+2] == 0xBF) && // && . != #xFEFF 72 | !(b[i+1] == 0xBF && (b[i+2] == 0xBE || b[i+2] == 0xBF)))) 73 | } 74 | 75 | // Check if the character at the specified position is NUL. 76 | func is_z(b []byte, i int) bool { 77 | return b[i] == 0x00 78 | } 79 | 80 | // Check if the beginning of the buffer is a BOM. 81 | func is_bom(b []byte, i int) bool { 82 | return b[0] == 0xEF && b[1] == 0xBB && b[2] == 0xBF 83 | } 84 | 85 | // Check if the character at the specified position is space. 86 | func is_space(b []byte, i int) bool { 87 | return b[i] == ' ' 88 | } 89 | 90 | // Check if the character at the specified position is tab. 91 | func is_tab(b []byte, i int) bool { 92 | return b[i] == '\t' 93 | } 94 | 95 | // Check if the character at the specified position is blank (space or tab). 96 | func is_blank(b []byte, i int) bool { 97 | //return is_space(b, i) || is_tab(b, i) 98 | return b[i] == ' ' || b[i] == '\t' 99 | } 100 | 101 | // Check if the character at the specified position is a line break. 102 | func is_break(b []byte, i int) bool { 103 | return (b[i] == '\r' || // CR (#xD) 104 | b[i] == '\n' || // LF (#xA) 105 | b[i] == 0xC2 && b[i+1] == 0x85 || // NEL (#x85) 106 | b[i] == 0xE2 && b[i+1] == 0x80 && b[i+2] == 0xA8 || // LS (#x2028) 107 | b[i] == 0xE2 && b[i+1] == 0x80 && b[i+2] == 0xA9) // PS (#x2029) 108 | } 109 | 110 | func is_crlf(b []byte, i int) bool { 111 | return b[i] == '\r' && b[i+1] == '\n' 112 | } 113 | 114 | // Check if the character is a line break or NUL. 115 | func is_breakz(b []byte, i int) bool { 116 | //return is_break(b, i) || is_z(b, i) 117 | return ( // is_break: 118 | b[i] == '\r' || // CR (#xD) 119 | b[i] == '\n' || // LF (#xA) 120 | b[i] == 0xC2 && b[i+1] == 0x85 || // NEL (#x85) 121 | b[i] == 0xE2 && b[i+1] == 0x80 && b[i+2] == 0xA8 || // LS (#x2028) 122 | b[i] == 0xE2 && b[i+1] == 0x80 && b[i+2] == 0xA9 || // PS (#x2029) 123 | // is_z: 124 | b[i] == 0) 125 | } 126 | 127 | // Check if the character is a line break, space, or NUL. 128 | func is_spacez(b []byte, i int) bool { 129 | //return is_space(b, i) || is_breakz(b, i) 130 | return ( // is_space: 131 | b[i] == ' ' || 132 | // is_breakz: 133 | b[i] == '\r' || // CR (#xD) 134 | b[i] == '\n' || // LF (#xA) 135 | b[i] == 0xC2 && b[i+1] == 0x85 || // NEL (#x85) 136 | b[i] == 0xE2 && b[i+1] == 0x80 && b[i+2] == 0xA8 || // LS (#x2028) 137 | b[i] == 0xE2 && b[i+1] == 0x80 && b[i+2] == 0xA9 || // PS (#x2029) 138 | b[i] == 0) 139 | } 140 | 141 | // Check if the character is a line break, space, tab, or NUL. 142 | func is_blankz(b []byte, i int) bool { 143 | //return is_blank(b, i) || is_breakz(b, i) 144 | return ( // is_blank: 145 | b[i] == ' ' || b[i] == '\t' || 146 | // is_breakz: 147 | b[i] == '\r' || // CR (#xD) 148 | b[i] == '\n' || // LF (#xA) 149 | b[i] == 0xC2 && b[i+1] == 0x85 || // NEL (#x85) 150 | b[i] == 0xE2 && b[i+1] == 0x80 && b[i+2] == 0xA8 || // LS (#x2028) 151 | b[i] == 0xE2 && b[i+1] == 0x80 && b[i+2] == 0xA9 || // PS (#x2029) 152 | b[i] == 0) 153 | } 154 | 155 | // Determine the width of the character. 156 | func width(b byte) int { 157 | // Don't replace these by a switch without first 158 | // confirming that it is being inlined. 159 | if b&0x80 == 0x00 { 160 | return 1 161 | } 162 | if b&0xE0 == 0xC0 { 163 | return 2 164 | } 165 | if b&0xF0 == 0xE0 { 166 | return 3 167 | } 168 | if b&0xF8 == 0xF0 { 169 | return 4 170 | } 171 | return 0 172 | 173 | } 174 | -------------------------------------------------------------------------------- /src/meson.build: -------------------------------------------------------------------------------- 1 | executable(app_id, 2 | 'application.vala', 3 | 'window.vala', 4 | 'Granite/Accels.vala', 5 | 'Granite/ModeSwitch.vala', 6 | 7 | c_args: ['-include', 'config.h'], 8 | link_args: '-lm', 9 | dependencies: [dependency('gtk+-3.0'), dependency('gtksourceview-3.0')], 10 | install: true 11 | ) 12 | --------------------------------------------------------------------------------