<//: For convenience, some instructions will take literal arrays of characters
//: (text or strings).
//:
//: Instead of quotes, we'll use [] to delimit strings. That'll reduce the
//: need for escaping since we can support nested brackets. And we can also
//: imagine that 'recipe' might one day itself be defined in Mu, doing its own
//: parsing.
void test_string_literal() {
load(
"def main [\n"
" 1:address:array:character <- copy [abc def]\n"
"]\n"
);
CHECK_TRACE_CONTENTS(
"parse: ingredient: {\"abc def\": \"literal-string\"}\n"
);
}
void test_string_literal_with_colons() {
load(
"def main [\n"
" 1:address:array:character <- copy [abc:def/ghi]\n"
"]\n"
);
CHECK_TRACE_CONTENTS(
"parse: ingredient: {\"abc:def/ghi\": \"literal-string\"}\n"
);
}
:(before "End Mu Types Initialization")
put(Type_ordinal, "literal-string", 0);
:(before "End next_word Special-cases")
if (in.peek() == '[') {
string result = slurp_quoted(in);
skip_whitespace_and_comments_but_not_newline(in);
return result;
}
:(code)
string slurp_quoted(istream& in) {
ostringstream out;
assert(has_data(in)); assert(in.peek() == '['); out << static_cast<char>(in.get()); // slurp the '['
if (is_code_string(in, out))
slurp_quoted_comment_aware(in, out);
else
slurp_quoted_comment_oblivious(in, out);
return out.str();
}
// A string is a code string (ignores comments when scanning for matching
// brackets) if it contains a newline at the start before any non-whitespace.
bool is_code_string(istream& in, ostream& out) {
while (has_data(in)) {
char c = in.get();
if (!isspace(c)) {
in.putback(c);
return false;
}
out << c;
if (c == '\n') {
return true;
}
}
return false;
}
// Read a regular string. Regular strings can only contain other regular
// strings.
void slurp_quoted_comment_oblivious(istream& in, ostream& out) {
int brace_depth = 1;
while (has_data(in)) {
char c = in.get();
if (c == '\\') {
slurp_one_past_backslashes(in, out);
continue;
}
out << c;
if (c == '[') ++brace_depth;
if (c == ']') --brace_depth;
if (brace_depth == 0) break;
}
if (!has_data(in) && brace_depth > 0) {
raise << "unbalanced '['\n" << end();
out.clear();
}
}
// Read a code string. Code strings can contain either code or regular strings.
void slurp_quoted_comment_aware(istream& in, ostream& out) {
char c;
while (in >> c) {
if (c == '\\') {
slurp_one_past_backslashes(in, out);
continue;
}
if (c == '#') {
out << c;
while (has_data(in) && in.peek() != '\n') out << static_cast<char>(in.get());
continue;
}
if (c == '[') {
in.putback(c);
// recurse
out << slurp_quoted(in);
continue;
}
out << c;
if (c == ']') return;
}
raise << "unbalanced '['\n" << end();
out.clear();
}
:(after "Parsing reagent(string s)")
if (starts_with(s, "[")) {
if (*s.rbegin() != ']') return; // unbalanced bracket; handled elsewhere
name = s;
// delete [] delimiters
name.erase(0, 1);
strip_last(name);
type = new type_tree("literal-string", 0);
return;
}
//: Unlike other reagents, escape newlines in literal strings to make them
//: more friendly to trace().
:(after "string to_string(const reagent& r)")
if (is_literal_text(r))
return emit_literal_string(r.name);
:(code)
bool is_literal_text(const reagent& x) {
return x.type && x.type->name == "literal-string";
}
string emit_literal_string(string name) {
size_t pos = 0;
while (pos != string::npos)
pos = replace(name, "\n", "\\n", pos);
return "{\""+name+"\": \"literal-string\"}";
}
size_t replace(string& str, const string& from, const string& to, size_t n) {
size_t result = str.find(from, n);
if (result != string::npos)
str.replace(result, from.length(), to);
return result;
}
void strip_last(string& s) {
if (!s.empty()) s.erase(SIZE(s)-1);
}
void slurp_one_past_backslashes(istream& in, ostream& out) {
// When you encounter a backslash, strip it out and pass through any
// following run of backslashes. If we 'escaped' a single following
// character, then the character '\' would be:
// '\\' escaped once
// '\\\\' escaped twranger 1.9.0b5
==============
[![Build Status](https://travis-ci.org/ranger/ranger.svg?branch=master)](https://travis-ci.org/ranger/ranger)
ranger is a console file manager with VI key bindings. It provides a
minimalistic and nice curses interface with a view on the directory hierarchy.
It ships with `rifle`, a file launcher that is good at automatically finding
out which program to use for what file type.
![screenshot](https://raw.githubusercontent.com/ranger/ranger-assets/master/screenshots/screenshot.png)
This file describes ranger and how to get it to run. For instructions on the
usage, please read the man page. See `HACKING.md` for development specific
information.
For configuration, check the files in `ranger/config/` or copy the
default config to `~/.config/ranger` with `ranger --copy-config`.
The `examples/` directory contains several scripts and plugins that demonstrate how
ranger can be extended or combined with other programs. These files can be
found in the git repository or in `/usr/share/doc/ranger`.
A note to packagers: Versions meant for packaging are listed in the changelog
on the website.
About
-----
* Authors: see `AUTHORS` file
* License: GNU General Public License Version 3
* Website: http://ranger.nongnu.org/
* Download: http://ranger.nongnu.org/ranger-stable.tar.gz
* Bug reports: https://github.com/ranger/ranger/issues
* git clone http://git.sv.gnu.org/r/ranger.git
Design Goals
------------
* An easily maintainable file manager in a high level language
* A quick way to switch directories and browse the file system
* Keep it small but useful, do one thing and do it well
* Console based, with smooth integration into the unix shell
Features
--------
* UTF-8 Support (if your python copy supports it)
* Multi-column display
* Preview of the selected file/directory
* Common file operations (create/chmod/copy/delete/...)
* Renaming multiple files at once
* VIM-like console and hotkeys
* Automatically determine file types and run them with correct programs
* Change the directory of your shell after exiting ranger
* Tabs, bookmarks, mouse support
Dependencies
------------
* Python (`>=2.6` or `>=3.1`) with the `curses` module
and (optionally) wide-unicode support.
* A pager (`less` by default)
Optional:
* The `file` program for determining file types
* The python module `chardet`, in case of encoding detection problems
* `sudo` to use the "run as root"-feature
* `w3m` for the `w3mimgdisplay` program to preview images
Optional, for enhanced file previews (with `scope.sh`):
* `img2txt` (from `caca-utils`) for ASCII-art image previews
* `highlight` or `pygmentize` for syntax highlighting of code
* `atool`, `bsdtar` and/or `unrar` for previews of archives
* `lynx`, `w3m` or `elinks` for previews of html pages
* `pdftotext` for pdf previews
* `transmission-show` for viewing bit-torrent information
* `mediainfo` or `exiftool` for viewing information about media files
* `odt2txt` for OpenDocument text files (`odt`, `ods`, `odp` and `sxw`)
Installing
----------
Use the package manager of your operating system to install ranger.
Note that ranger can be started without installing by simply running `ranger.py`.
To install ranger manually:
```
sudo make install
```
This translates roughly to:
```
sudo python setup.py install --optimize=1 --record=install_log.txt
```
This also saves a list of all installed files to `install_log.txt`, which you can
use to uninstall ranger.
Getting Started
---------------
After starting ranger, you can use the Arrow Keys or `h` `j` `k` `l` to navigate, `Enter`
to open a file or type `Q` to quit. The third column shows a preview of the
current file. The second is the main column and the first shows the parent
directory.
Ranger can automatically copy default configuration files to `~/.config/ranger`
if you run it with the switch `--copy-config`. See `ranger --help` for a
description of that switch. Also check `ranger/config/` for the default
configuration.