Skip to content

aaronroyer/styles

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

58 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Styles

plain text stylesheets

Introduction

Styles is an attempt to apply useful CSS concepts to plain text processing. Rules operate on lines of text rather than DOM elements. Not all concepts from CSS are applicable. The most useful ones are:

  • Selectors (including String and Regexp) to match lines
  • Application of properties to matched lines with the familiar last-one-wins model

Dependencies

  • Ruby 1.9 or better

Installation

Install with RubyGems.

$ gem install styles

Usage

Create a stylesheet

$ styles --edit my_styles

This will create a new stylesheet in ~/.styles (by default) called my_styles.rb and open it in your $EDITOR. If you don't specify a stylesheet name it will use 'default'.

'important' - {
  color: blue,
  font_weight: bold,
  text_decoration: underline
}

'warning' - {
  background_color: yellow
}

/annoying/i - {
  display: none
}

/\d{3}-\d{3}-\d{4}/ - {
  # match_color is like color except it applies to the matched portion of the line
  match_color: green
}

:blank - {
  display: none
}

Stylesheets are written in a pure Ruby DSL that is vaguely similar to CSS. Instead of operating on DOM elements, rules operate on lines of text. Rules are specified with a selector, a -, and a hash of properties. A selector can be one of three things.

  • String - matches if a line contains the string
  • Regexp - matches if the line matches regular expression
  • Symbol - matches certain special types of lines, examples include :blank and :any

To leverage you CSS knowledge, some familiar properties are available. You may notice that their form and the syntax in general is altered to make everything valid Ruby. There are also some others that have no CSS counterparts. See below for a list of all properties and values.

Apply the stylesheet to some text

Pipe some text to styles, specifying which stylesheet you want to use.

Lets say example.txt contains this

this is an important line
this line is warning you about something
THIS LINE IS SUPER ANNOYING!
here is my phone number: 555-234-6789

the line before this is blank

Let’s use the stylesheet we just created above.

The annoying and blank lines have been hidden and, if your terminal supports it, you should see the colors applied as you expect them.

More Examples

Only display interesting lines

Stylesheet

:all - {
  display: none
}

'interesting' - {
  display: block # Could also use: display: true
}

/(very|quite|most) interesting/i - {
  background_color: green
}

Input

a line
another line
nothing to see here
this is interesting
this is VERY interesting
this is not

Output

Do crazy stuff with CSS-style layout properties

Stylesheet

'gimmicky' - {
  padding: 1,
  margin: 2,
  border: 'solid blue',
  width: 30,
  text_align: right
}

Input

a bit gimmicky

Output

Do arbitrary processing on lines

Stylesheet

'password' - {
  function: ->(line) { line.sub(/(password is:) (\S+)/, '\1 XXXXXX') }
}

Input

the password is: 5up3rs3cr3t

Output

Reference

Selectors

Selectors are used to match lines of input. They are like CSS selectors but instead of matching DOM elements they match some or all of the content of a line.

There are three types of selector: String, Regexp, and Symbol.

String

Strings are the simplest type of selector. A line matches a String selector when the line text includes the string. The string must exactly match and is case-sensitive.

The String selector

'example'

matches these lines.

example
  example
this is an example
example is here

And does not match these lines.

random other stuff
EXAMPLE
this is an Example

ANSI color codes in the line are ignored when matching. So a selector 'is red' will match the following line.

this is \e[31mred\e[0m

Note that in your terminal the 3rd word would be red and you would not see the color code characeters, even though they are present in the line. These are stripped before attempting the match to do what (I think) is expected.

Regexp

Regexp selectors are perhaps the most versatile. If any part of the line matches the Regexp then the line matches the selector.

You can use this to make simple string matches case-insensitive, for example you could use

/example/i

for a case-insensitive version of the example for the String selector. You can, of course, do more complicated things using the crazy power of Ruby Regexps.

ANSI color codes in the line are ignored when matching, as with String selectors.

Symbol

Symbol selectors match some common types of lines, for convenience.

Right now there are four valid Symbol selectors: :blank, :empty, :any, and :all

:blank - matches lines that are either completely empty or only contain whitespace

:empty - matches lines that are completely empty

:any - matches any line

:all - matches any line (synonym of :any)

Properties

Text Styling:

Layout:

Miscellaneous:

Text Styling Properties


background_color

Sets the background color (where supported) for the matched line

Valid values: black, red, green, yellow, blue, magenta, cyan, white

See also: match_background_color

'back' - {
  background_color: blue
}

color

Sets the foreground color (where supported) for the matched line

Valid values: black, red, green, yellow, blue, magenta, cyan, white

See also: match_color

/color/i - {
  color: red
}

font_weight

Makes the text bold (where supported) or normal weight for the matched line

Valid values: normal, bold

'bold' - {
  font_weight: bold
}
'normal' - {
  font_weight: normal
}

text_decoration

Applies various text decorations (where supported) to the matched line

Valid values: none, underline, line_through, strikethrough, blink

strikethrough is a synonym for line_through

/^decor/ - {
  text_decoration: underline
}

match_background_color

Sets the background color (where supported) for the matched portion of a line

Valid values: black, red, green, yellow, blue, magenta, cyan, white

Multiple colors are applied in the same way as with match_color.

Examples
'test' - {
  match_background_color: blue
}

/\d+/ - {
  match_background_color: red
}


match_color

Sets the color (where supported) for the matched portion of a line

Valid values: black, red, green, yellow, blue, magenta, cyan, white

If a String selector is used then the color is applied to each matching portion of the string in the matched line. For a Regexp selector, if there are no groups the color is applied portions of the line that the whole Regexp matches. If there are groups then you can specify an Array of colors to be applied to the respective groups in the Regexp.

'test' - {
  match_color: blue
}
/\d+/ - {
  match_color: red
}
/(m\w*) (m\w*)/ - {
  match_color: [blue, green]
}

match_font_weight

Makes the text bold (where supported) or normal weight for the matched portion of a line

Valid values: normal, bold

Multiple match font weights are applied in the same way as with match_color.

Example
'bold' - {
  match_font_weight: bold
}


match_text_decoration

Applies various text decorations (where supported) to the matched portion of a line

Valid values: none, underline, line_through, strikethrough, blink

strikethrough is a synonym for line_through

/^decor\w+/ - {
  match_text_decoration: underline
}

Layout Properties


border

Adds a one-character width border around matched lines. There are two attributes of the border that can be configured: style and color.

Valid style values: solid, dashed, dotted, double

dotted is a synonym for dashed

Valid color values: black, red, green, yellow, blue, magenta, cyan, white

Style must be specified, color is optional. There is no border width configuration as with CSS. If only a style is specified you do not need to put the value in a string. If you are specifying a color along with the style you must use a string.

'test' - {
  border: 'solid red'
}

display

This may do more in the future, but for now just basically specifies whether to hide or show particular lines. This is generally useful for filtering out lines you don't want to see and overriding the hiding later if necessary.

none and false will cause the line to not display. Any other value will cause it to display as normal. It is recommended to use true or block to show lines as values line inline may have a different meaning later.

Valid values: block, inline, inline_block, none, true, false

# Hide lines that contain a particular string

'test' - {
  display: none
}
# Hide all lines except ones that contain a phone number

:all - {
  display: none
}

/\d{3}-\d{3}-\d{4}/ - {
  display: block
}

margin

Adds space around a line, outside any border or padding, if present. For top and bottom margins, lines are added above and below the line. For left and right margins spaces are added on either side of the line.

Values are specified as integers with no units. If the margin should be the same on every side, use a single integer for a value. If margins should be different, use a string with multiple integers. A value of auto can also be used and will center the line in the terminal if specified for the left or right margin.

Like CSS, sides are configured in this order: top, right, bottom, left. Any number of sides can be specified (that is: if you only give 2 integers then only top and right will be set).

You can also use the property names margin_top, margin_right, margin_bottom, and margin_left to specify a margin for a single side.

'special' - {
  margin: 1
}
# Different margins can be specified for each side
# Order is: top, right, bottom, left
'special' - {
  margin: '2 1 1 5'
}

# You can also just set the margin for one side
'move me to the right' - {
  margin_left: 10
}

# The following sets a margin of 3 on every side except for the bottom, which is 1
'another example' - {
  margin: 3,
  margin_bottom: 1
}

padding

Adds space around a line, inside any border or margin, if present. For top and bottom padding, lines are added above and below the line. For left and right padding spaces are added on either side of the line.

Valid values are integers with no units. If the padding should be the same on every side, use a single integer for a value. If padding should be different, use a string with multiple integers.

Like CSS, sides are configured in this order: top, right, bottom, left. Any number of sides can be specified (that is: if you only give 2 integers then only top and right will be set).

You can also use the property names padding_top, padding_right, padding_bottom, and padding_left to specify padding for a single side.

# Different padding can be specified for each side
# Order is: top, right, bottom, left
'special' - {
  padding: '2 1 1 5'
}

# You can also just set the padding for one side
'move me to the right' - {
  padding_left: 10
}

# The following sets padding of 3 on every side except for the bottom, which is 1
'another example' - {
  padding: 3,
  padding_bottom: 1
}

text_align

Aligns text within the available width it can occupy. This behaves differently depending on whether other layout properties are applied to the line.

If there is no padding, border, or margin applied to the line, the text is aligned according to the terminal width. right aligned lines will be moved as far right in the terminal as possible. center aligned lines will appear in the middle of the terminal. left alignment usually does nothing, but it can be used to override previous text_align settings. If the terminal width cannot be determined, 80 is used. If the line is longer than the terminal is wide then no alignment will be applied.

If there is any of padding, border, or margin applied to the line, then the text of the line is aligned, inside any border and padding, within the width of the line, set by the width property. If no width is specified, or the length of the line text exceeds the width, then nothing is done.

Valid values: left, right, center


Sets the width of the line. The W3C box model is used, so this specifies the horizontal area inside any border and padding for the line.

A valid value is an integer with no units.



function

This is a catch-all property that allows you to process a line with arbitrary Ruby code.

The value for the function property is any callable object (like a lambda or a proc). The "stabby lambda" may be the most convenient to use.

The callable should have one parameter. The callable will be called with the text of the matched line as its only argument. Whatever is returned will replace the line. An empty string will cause a blank line to be output. To skip the line, return nil.

function processing works with the line exactly as it was input, before any other properties are applied. Other properties are applied afterward, if any.

Stylesheet

/loud/i - {
  function: ->(line) { line.downcase }
}

Input

normal volume
TOO LOUD
ALSO TOO LOUD
this is ok

Output

normal volume
too loud
also too loud
this is ok

Stylesheet

'temperature' - {
  function: lambda do |line|
    temp = line.scan(/\d+/).first.to_i
    if temp < 80
      nil # No output, line is skipped
    elsif temp >= 90 && temp < 100
      "WARNING: #{line}"
    elsif temp >= 100
      "EMERGENCY: #{line}"
    else
      line
    end
  end
}

Input

the temperature is 75 degrees
the temperature is 82 degrees
the temperature is 90 degrees
the temperature is 103 degrees
the temperature is 95 degrees
the temperature is 88 degrees
the temperature is 77 degrees

Output

the temperature is 82 degrees
WARNING: the temperature is 90 degrees
EMERGENCY: the temperature is 103 degrees
WARNING: the temperature is 95 degrees
the temperature is 88 degrees

License

Styles is MIT licensed (see LICENSE.txt)

About

plain text stylesheets

Resources

License

Stars

Watchers

Forks

Packages

No packages published

Languages