1 /*
2 	 -------------------------------------------------------------------
3 
4 	 Copyright (C) 2014, Edwin van Leeuwen
5 
6 	 This file is part of plotd plotting library.
7 
8 	 Plotd is free software; you can redistribute it and/or modify
9 	 it under the terms of the GNU General Public License as published by
10 	 the Free Software Foundation; either version 3 of the License, or
11 	 (at your option) any later version.
12 
13 	 Plotd is distributed in the hope that it will be useful,
14 	 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 	 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16 	 GNU General Public License for more details.
17 
18 	 You should have received a copy of the GNU General Public License
19 	 along with Plotd. If not, see <http://www.gnu.org/licenses/>.
20 
21 	 -------------------------------------------------------------------
22 	 */
23 
24 module cli.options;
25 
26 import std.conv : to;
27 import std.string : split;
28 
29 import docopt : ArgValue;
30 
31 version( unittest ) {
32 	import std.algorithm : equal;
33 	import std.stdio : writeln;
34 	import docopt : docopt;
35 }
36 
37 import cli.column;
38 
39 /// Merge given associative arrays
40 V[K] merge( K, V )( V[K] aaBase, in V[K] aa ) {
41 	foreach ( k, v; aa )
42 		aaBase[k] = v;
43 	return aaBase;
44 }
45 
46 ///
47 unittest {
48 	auto aa1 = ["x" : 1.0, "y": 2.0];
49 	auto aa2 = ["y":3.0];
50 	assert( aa1.merge( aa2 ) == ["x" : 1.0, "y": 3.0] );
51 	aa2 = ["y":3.0, "z":4.0];
52 	assert( aa1.merge( aa2 ) == ["x" : 1.0, "y": 3.0, "z":4.0] );
53 }
54 
55 auto helpText = "Usage: plotcli [-f] [-o OUTPUT] [-d FORMAT]
56 
57 Plotcli is a plotting program that will plot data from provided data streams (files). It will ignore any lines it doesn't understand, making it possible to feed it \"dirty\" streams/files. All options can also be provided within the stream by using the prefix #plotcli (e.g. #plotcli -d x,y).
58 
59 Options:
60   -f          Follow the stream, i.e. keep listening for new lines.
61   -d FORMAT		String describing the content of each row. Different row formats supported: x, y and h, with h indication histogram data. For more information see Data format section.
62   -o OUTPUT		Outputfile (without extension).
63 
64 Data format:
65   Using -d it is possible to specify what each column in your data file represents. Supported formats are:
66 
67   x,y		The x and y coordinate for points
68   lx,ly	Line data
69   h			Histogram data
70 	..		Extrapolate from previous options, i.e. x,y,.. -> x,y,x,y,..
71 
72 	Examples: x,y,y or h,x,y. When there are more ys provided than xs (or vice versa) the last x will be matched to all remaining ys.
73 
74   Data ids: plotcli by default does a good job of figuring out which x and y data belong together, but you can optionally provide an numeric id to make this completely clear. I.e. x1,y1. Data ids always need to directly follow the format type (before plot ids).
75 
76   Plot ids: if you want to plot the data to different figures you can add a letter/name at the end: xa,ya or x1a,y1a. This plot id will be appended to the OUTPUT file name. 
77 
78 	Extrapolatin (..): plotcli will try to extrapolate from your previous options. This also works for simple plot ids. I.e. if you want a separate histogram for each column: ha,hb,.. results in ha,hb,hc,hd,he etc. Other examples: y,.. -> y,y,y,y etc. x,y,y,.. -> x,y,y,y,y etc.
79 
80 ";
81 
82 /* Future options
83 
84 	--adaptive MODE (not adaptive, scrolling, full) First two need bounds or alternatively adaptive-cache for initial bounds 
85 	--adaptive-cache CACHESIZE (does it stop being adaptive after this or does it stop caching? Maybe combine with not adaptive or scrolling)
86 	--bounds BOUNDS (minx,maxx,miny,maxy) sets default MODE to not
87 	--image	IMAGETYPE (pdf,png)
88 	--xlabel XLABEL
89 	--ylabel YLABEL
90 	--debug 		Output lines that are not successfully parsed
91 
92 Future Data formats:
93   hx,hy	2D Histogram data (Not supported yet)
94 
95 You can also start a new plot by passing a new output file name in the stream (e.g. #plotcli -o newplot).
96 
97 	*/
98 
99 struct Settings {
100 	Formats formats;
101 	string outputFile = "plotcli";
102 	bool follow = false;
103 }
104 
105 unittest {
106 	Settings settings;
107 	assert( settings.formats.empty );
108 	assert( settings.outputFile == "plotcli" );
109 }
110 
111 Settings updateSettings( Settings settings, ArgValue[string] options ) {
112 	if ( !options["-d"].isNull ) 
113 	{
114 		settings.formats = parseDataFormat( options["-d"].to!string );
115 	}
116 	if ( !options["-o"].isNull )
117 		settings.outputFile = options["-o"].to!string;
118 	if ( options["-f"].isTrue )
119 		settings.follow = true;
120 	return settings;
121 }
122 
123 unittest {
124 	Settings settings;
125 	auto args = docopt(helpText, [], true, "plotcli");
126 	assert( args["-d"].isNull );
127 	settings = settings.updateSettings( 
128 			docopt(helpText, [], true, "plotcli") );
129 	assert( settings.formats.empty );
130 	assert( settings.outputFile == "plotcli" );
131 
132 	settings = settings.updateSettings( 
133 			docopt(helpText, ["-d", "x,y"], true, "plotcli") );
134 	assert( settings.formats.front.mode == "x" );
135 	assert( settings.outputFile == "plotcli" );
136 
137 	settings = settings.updateSettings( 
138 			docopt(helpText, ["-o", "name"], true, "plotcli") );
139 	assert( settings.outputFile == "name" );
140 	assert( settings.follow == false );
141 
142 	settings = settings.updateSettings( 
143 			docopt(helpText, ["-f"], true, "plotcli") );
144 	assert( settings.follow == true );
145 	settings = settings.updateSettings( 
146 			docopt(helpText, ["-o", "name"], true, "plotcli") );
147 	assert( settings.follow == true );
148 }