The Vedeu DSL
Coupled with the API (for interacting with the running client application), the DSL provides the mechanism to configure aspects of your application whilst using Vedeu.
Interfaces
An Interface is a basic element in the GUI. You can think of it as a container for a portion of the terminal screen. Interfaces can be set to be show or hidden, and combined into groups to form the different 'screens' of your application.
Much of the behavior of an Interface comes from child objects that are defined under the Interface. These objects are described in more detail in their respective sections below.
Here is an example of declarations for an interface
block:
interface :main do
visible true # whether to show the interface
focus! # focus this interface
cursor true # Show the cursor when this section is focused
colour foreground: '#ffffff', # set interface foreground
background: '#000033' # and background colors
group :general # set interface group
geometry do
# size and position details
end
border do
# border properties
end
keymap do
# keymap that is in effect when this interface is focused
end
end
The content for an interface is handled by a 'view'. More details on these can be found here: Views
Declaring interface sub-objects
Every object in the DSL besides interface itself is defined for a
particular interface. This can either be declared implicitly by
defining the object inside an interface
block or explicitly, by
passing the interface name as a first argument to the declaration.
That is, these are equivalent ways to declare a Geometry for an existing interface
interface :main do
geometry do
# some geometry
end
# some other declarations
end
or you can say
interface :main do
# some other declarations
end
geometry :main do
# some geometry
end
Borders
Provides a mechanism to help configure borders in Vedeu.
Creating a new named border
Setting a title for the border
Customising the appearance of the border
Enabling/disabling the border
Enabling/disabling an aspect of the border
and false.
Geometry
Geometry allows the configuration of the position and size of an interface. Within Vedeu, as the same for ANSI terminals, has the origin at top-left, y = 1, x = 1. The ‘y’ coordinate is deliberately first.
The Geometry DSL can be used within the Interface DSL or standalone. Here are example of declarations for a ‘geometry` block:
A standalone geometry definition:
Vedeu.geometry :some_interface do
height 5 # Sets the height of the view to 5
width 20 # Sets the width of the view to 20
x 3 # Start drawing 3 spaces from left
y 10 # Start drawing 10 spaces from top
xn 30 # Stop drawing 30 spaces from the left
yn 20 # Stop drawing 20 spaces from top
end
An interface including a geometry definition:
Vedeu.interface :some_interface do
geometry do
height 5
width 20
x 3
y 10
xn 30
yn 20
end
# ... some code here
end
If a declaration is omitted for ‘height` or `width` the full remaining space available in the terminal will be used. `x` and `y` both default to 1.
You can also make a geometry declaration dependent on another view:
Vedeu.interface :other_panel do
# ... some code here
end
Vedeu.interface :main do
geometry do
height 10
y { use(:other_panel).south }
end
# ... some code here
end
This view will begin just below “other_panel”.
This crude ASCII diagram represents a Geometry within Vedeu, each of the labels is a value you can access or define.
x north xn # north: y - 1
y +--------------+ # top: y
| top | # west: x - 1
| | # left: x
west | left right | east # right: xn
| | # east: xn + 1
| bottom | # bottom: yn
yn +--------------+ # south: yn + 1
south
Creating a new named geometry
Setting the interface dimensions
Align the interface/view horizontally or vertically within the terminal.
Groups
Interfaces can be configured to be part of a named group. Once an interface is a member of group, the group can be affected by other controls. For example, assuming the client application is a simple Git client, it may have a group called ‘commit’. The ‘commit’ group will contain the interfaces ‘diff’ (to show the changes), ‘staged’ (to show which files are staged) and ‘unstaged’. A refresh of the ‘commit’ group would cause all interfaces belonging to the group to refresh. Similarly, showing or hiding the group would of course, show or hide the interfaces of that group.
Creating a new named group
Specify a new group of interfaces with a simple DSL. Creating a group with the same name as an existing group overwrites the existing group.
The example below resembles ‘vim’ (the popular terminal-based text editor):
Vedeu.group :title_screen do
add :welcome_interface
# ... some code
end
Vedeu.group :main_screen do
add :editor_interface
add :status_interface
add :command_interface
# ... some code
end
or more succinctly:
Vedeu.group :main_screen do
members :editor_interface,
:status_interface,
:command_interface
# ... some code
end
or when defining an interface:
Vedeu.interface :some_interface do
group :some_group
# ... some code
end
Add interfaces to groups
Add the named interface to this group.
Vedeu.group :main_screen do
add :editor_interface
end
Keymaps
You can define keymaps by name which matches a defined interface. When that interface is in focus, keys pressed as part of this definition will affect that interface. This allows you to form context driven behaviour for your application.
Creating a new named group
Define actions for keypresses for when specific interfaces are in focus. Unless an interface is specified, the key will be assumed to be global, meaning its action will happen regardless of the interface in focus.
Vedeu.keymap :my_interface do
key('s') { Vedeu.trigger(:save) }
key('h', :left) { Vedeu.trigger(:left) }
key('j', :down) { Vedeu.trigger(:down) }
key('p') do
# ... some code
end
# ... some code
end
# or...
Vedeu.keys :my_interface do
# ... some code
end
# or...
Vedeu.interface :my_interface do
keymap do
# ... some code
end # or...
keys do
# ... some code
end
end
Menus
Provides the mechanism to create menus within client applications and use events to drive them. Add an individual item to the menu. Define the items for the menu. Most powerful when used with one of your model classes.
In the :my_playlist example below, your ‘Track` model may return a collection of tracks to populate the menu.
Vedeu. :my_menu do
items [:item_1, :item_2, :item_3]
end
Vedeu. :my_playlist do
items Track.all_my_favourites
end
Creating a new named menu
Register a menu by name which will display a collection of items for your users to select; and provide interactivity within your application.
Views
There are two ways to construct views with Vedeu. You would like to draw the view to the screen immediately (immediate render) or you want to save a view to be drawn when you trigger a refresh event later (deferred view).
Both of these approaches require that you have defined an interface (or ‘visible area’) first. You can find out how to define an interface with Vedeu below or in Vedeu::Interfaces::DSL. The examples in ‘Immediate Render’ and ‘Deferred View’ use these interface definitions: (Note: should you use these examples, ensure your terminal is at least 70 characters in width and 5 lines in height.)
Vedeu.interface :main do
geometry do
height 4
width 50
end
end
Vedeu.interface :title do
geometry do
height 1
width 50
x use('main').left
y use('main').north
end
end
Both of these approaches use a concept of Buffers in Vedeu. There are three buffers for any defined interface. These are imaginatively called: ‘back’, ‘front’ and ‘previous’.
The ‘back’ buffer is the content for an interface which will be shown next time a refresh event is fired globally or for that interface. So, ‘back’ becomes ‘front’.
The ‘front’ buffer is the content for an interface which is currently showing. When a refresh event is fired, again, globally or for that interface specifically, the content of this ‘front’ buffer is first copied to the ‘previous’ buffer, and then the current ‘back’ buffer overwrites this ‘front’ buffer.
The ‘previous’ buffer contains what was shown on the ‘front’ before the current ‘front’.
You can only write to either the ‘front’ (you want the content to be drawn immediately (immediate render)) or the ‘back’ (you would like the content to be drawn on the next refresh (deferred view)).
The basic view DSL methods look like this:
renders/views
|- view
|- lines
| |- line
| |- streams
| | |- stream
| | |- char
| |
| |- stream
| |- char
|
|- line
|- streams
| |- stream
| |- char
|
|- stream
|- char
renders/views
|- view
|- lines/line
|- streams/stream
|- char
Register an interface by name which will display output from an event or a command. This provides the means for you to define your the views of your application without their content.
Vedeu.interface :my_interface do
# ... some code
end
Immediate rendering
Deferred rendering
Authors Notes
The Rubydoc documentation has more specific information about the DSL methods demonstrated above: RubyDoc.
I've tried to write the DSL in a way which makes it read nice; believing that this will make it easier to use. I hope this is the case for you.