delphidabbler / pashi

Pascal syntax highlighter targetted at Delphi
https://delphidabbler.com/software/pashi
Other
21 stars 7 forks source link

Make `--verbosity` command more flexible. #15

Open delphidabbler opened 3 years ago

delphidabbler commented 3 years ago

Allow combinations of levels, connected by plus signs:

So:

The current parameters ˙normal˙ and quiet would be equivalent to info+warn+error and error respectively.

Other synonyms could be silent for display nothing and loud for normal.

delphidabbler commented 3 years ago

Consider possibility of following linux model and making program silent, except for error messages, by default. Many linux programs print nothing if they execute successfully.

delphidabbler commented 3 years ago

One for v3 I think.

For further discussion see v3 Development Project

delphidabbler commented 3 years ago

Confirmed that v3 will change default verbosity to "quiet".

delphidabbler commented 3 years ago

Moved proposals to Google Docs file v3-design.

delphidabbler commented 2 years ago

Forget v3-design - there's only a PDF that can't be edited.

The following is what that document said about the --verbosity command changes in v3, with a few errors corrected.

There are three different types of output in PasHi 2.1, any of which could be in and on or off state. We could add a fourth state. They are / would be:

  1. debug - outputs information about every setting and input file name (inc & especially what's being read from config)
  2. info - outputs normal sign-on, sign-off messages
  3. warnings - displays warnings
  4. errors - displays errors

We will allow any of them to be on or off. The --verbosity command could then have the following syntax:

--verbosity <param>

Where

<param> := <switch-list> | <set> | <macro>
<switch-list> := <switch> {"," <switch>}
<set> := "[" [<state-list>] "]"
<state-list> := <state> {"," <state>}
<switch> := <state> ( "+" | "-" )
<state> := <debug-state> | <info-state> | <warning-state> | <error-state>
<debug-state> := "debug" | "d"
<info-state> := "info" | "i"
<warning-state> := "warning" | "warn" | "w"
<error-state> := "errors" | "error" | "err" | "e"
<macro> := "normal" | "no-warn" | "quiet" | "silent" | "standard"

Notes:

delphidabbler commented 2 years ago

This all seems a little over complicated. I think it could be simplified as follows.

The four states listed above will be retained:

  1. debug
  2. info
  3. warnings
  4. errors

Any number of states can be combined. Furthermore the output can be totally silenced.

--verbosity will always be followed by a single parameter. The parameter will either be a comma separated list of verbosity states or a special parameter indicating no output. The states that can be used in the comma separated list will be:

The above could be have their initial letters used as abbreviations. Maybe!

To switch off all output the parameter - can be used. none or silent could also be used as synonyms.

There are some v2 parameters & commands that may need to be supported (but possibly deprecated):

Note that --verbosity has short form -v and --quiet has short form -q.

delphidabbler commented 2 years ago

The above could be have their initial letters used as abbreviations. Maybe!

If this is done, it would be more friendly to just concatenate the required initial letters into a single "word" rather than insisting that the letters be comma separated.

It would be a bit tricky to parse though - first every possible word listed in the previous comment would have to be checked and only if none of those words were matches would the word be split into its component letters and each of those would have to be checked. Such a parameter could not contain commas.

delphidabbler commented 2 years ago

--verbosity will always be followed by a single parameter. The parameter will either be a comma separated list of verbosity states or a special parameter indicating no output.

Would + be a better separator than , in the parameter list? Or perhaps allow either.

delphidabbler commented 2 years ago

If the changes proposed in the later comments above are adopted then there's no reason not to make the changes in v2.x, without waiting for v3.

delphidabbler commented 2 years ago

If the changes proposed in the later comments above are adopted then there's no reason not to make the changes in v2.x, without waiting for v3.

If the changes to default verbosity in v3 proposed in issue #49 are adopted then the current verbosity default of info,warnings,errors will need to be flagged as deprecated since it will change to warnings,errors in v3.

delphidabbler commented 2 years ago

Although it seems sensible at first sight to exclude the synonyms, such as - and no-warn from the "set" values, it actually does no harm to allow them.

For e.g. no-warn+debug is the same as writing info+errors+debug. Similarly, -,info or silent,info is the same as info - pointless but valid! Even duplicating values does no harm since we are effectively dealing with sets, so no-warn+quiet = info+errors+errors = info+errors.

Allowing such combinations would greatly simplify parsing. We can define a map of symbol to set of verbosity values and simply get the union of all the relevant sets.

Here's some outline code:

type
  TVerbosityState = (vsDebug, vsInfo, vsWarnings, vsErrors):
  TVerbosityStates = set of TVerbosityState;
// ...
fVerbosityMap = TDictionary<string,TVerbosityStates>.Create(...);
fVerbosityMap.Add('debug', [vsDebug]);
fVerbosityMap.Add('info', [vsInfo]);
fVerbosityMap.Add('warnings', [vsWarnings]);
fVerbosityMap.Add('warn', [vsWarnings]);
// etc ...
fVerbosityMap.Add('-', []);
fVerbosityMap.Add('silent', []);
// ...
fVerbosityMap.Add('normal', [vsInfo,vsWarnings,vsErrors]);
// ...

We can then use fVerbosityMap to look up each element extracted from the parameter to (a) validate it and (b) form a union of the related sets. For example, say we have extracted two elements in array of string A, then the code, without validation, would look something like this:

var VerbositySet: TVerbosityStates := [];
for var Elem: string in A do
  VerbositySet := VerbositySet + fVerbosityMap[Elem];

Of course if the proposal to permit short form combinations of initial letters of the four states is accepted then the code would be complicated again!

delphidabbler commented 2 years ago

Adopting this mix and match approach to verbosity states will require changes to the code that writes to stderr to specify the required verbosity state, which will need to be tested against the verbosity options before writing.

Furthermore, if it is assumed that verbosity states are ignored by commands like --help and --version we also need code to force writing to stderr regardless of verbosity state.

delphidabbler commented 2 years ago

I'm implementing --inhibit-styling (issue #30) to use set notation for comma delimited lists, using curly brackets. This is useful to represent the empty set (silence in the case of --verbosity) as {}.

So it makes sense to do that for --verbosity too. So, I'm back to dropping the + separator.


I did this for --inhibit-styling originally because I couldn't get - to work as a parameter in v2.x, so I needed {} to inhibit no styling. However I've now fixed the problem with -, so I didn't have to use set notation after all. But I like the look of it so have kept it.

I think the set notation is good for distinguishing a set from a list.

For --inhibit-styling I implemented aliases in such a way the single element sets can omit the curly brackets. I also reintroduced - as an alias for {}.

delphidabbler commented 2 years ago

Considering changes needed to output different verbosity levels to stderr, here are some ideas.

Firstly we could interpose an additional level of abstraction between main code and the Windows output code. Something like:

type
  TOutputState = (osDebug, osInfo, osWarnings, osErrors);
  TOutputStates = set of TOutputState;

procedure TConsole.Write(const Text: string; OutputState: TOutputState);
var
  ANSIBytes: TBytes;  // text converted to ANSI byte stream
  State: TOutputState;
begin
  if OutputState in fConfig.OutputStates then
  begin
    ANSIBytes := TEncoding.Default.GetBytes(Text);
    TStdIO.Write(stdErr, Pointer(ANSIBytes)^, Length(ANSIBytes));
  end;
end;

Here, fConfig.OutputStates is a new property of type TOutputStates that stores the output states defined by the --verbosity command.

TConsole.Write is a new overloaded method of TConsole. The old, similar, method that called fSilent is to be removed, as is the fSilent flag.

delphidabbler commented 2 years ago

I've decided to implement in v2.x.

The following parameters will be supported:

Set parameters

Curly brackets surrounding zero or more of:

Sets containing one value may omit the curly brackets.

Aliases

Aliases will probably be allowed in sets (as discussed in earlier comments).

Depreciation & v3 changes

As noted above the normal parameter will need to be deprecated in v2 because the "normal", i.e. default, state in v3 is due to change from {info,warnings,errors} to {warnings,errors}. Therefore normal will either be misleading if it retains its v2 value or be confusing if it changes value.

Consequently normal will be deprecated in v2 and will be removed from v3. Instead v3 will use a new default parameter that is an alias for {warnings,errors}. The default in v3 will change to default!

Finally, the future of no-warn is up in the air. It was only included as a fudge for the rare cases when warnings needed to be turned off while leaving info & errors turned on. It may be deprecated in v2 and removed from v3.


There's also the --quiet command that's an alias for --verbosity {errors}. That seems a sensible choice, so I see no reason to get rid of it.

However it does suggest that, logically, a new --silent command would make sense that is an alias for {}.

delphidabbler commented 1 month ago

Considering changes needed to output different verbosity levels to stderr, here are some ideas.

Firstly we could interpose an additional level of abstraction between main code and the Windows output code. Something like:

type
  TOutputState = (osDebug, osInfo, osWarnings, osErrors);
  TOutputStates = set of TOutputState;

procedure TConsole.Write(const Text: string; OutputState: TOutputState);
var
  ANSIBytes: TBytes;  // text converted to ANSI byte stream
  State: TOutputState;
begin
  if OutputState in fConfig.OutputStates then
  begin
    ANSIBytes := TEncoding.Default.GetBytes(Text);
    TStdIO.Write(stdErr, Pointer(ANSIBytes)^, Length(ANSIBytes));
  end;
end;

Here, fConfig.OutputStates is a new property of type TOutputStates that stores the output states defined by the --verbosity command.

TConsole.Write is a new overloaded method of TConsole. The old, similar, method that called fSilent is to be removed, as is the fSilent flag.

This is all very well, except there is no fConfig field in TConsole. What we need to do is replace the Silent property with one that records the permitted output states that is set where Silent used to be set and check if OutputState is a member of that set.

delphidabbler commented 1 month ago

There are three different types of output in PasHi 2.1, any of which could be in and on or off state. We could add a fourth state. They are / would be:

  1. debug - outputs information about every setting and input file name (inc & especially what's being read from config)
  2. info - outputs normal sign-on, sign-off messages
  3. warnings - displays warnings
  4. errors - displays errors

Decided not implement debug: finding it hard to decide what to display in this mode. Everything other than the content of the config file is really difficult to implement in v2. Maybe if management of the command line is rewritten in v3 it would be possible.

Display of config file settings will now be achieved in --config-show command (see issue #84)