fvwm3 icon indicating copy to clipboard operation
fvwm3 copied to clipboard

Ideas for a new config syntax

Open lgsobalvarro opened this issue 3 years ago • 37 comments

With the aim of streamlining/modernizing FVWM3 syntax and trying to make it a bit more friendly for new users. I put forward the following ideas of how it could work.

This proposal is inspired by CSS/SASS.

Module invocation

Module {
	+I FvwmPager;
	+I FvwmButtons.RightPanel;
}

Functions

Functions {
	IconManClick {
		+I ThisWindow {
			(Raised, !Shaded, !Iconic, CurrentPage) Iconify;
			(!Raised) Raise;
			(Shaded) WinshowShade;
			(Iconic) Iconify;
			(AcceptsFocus) FlipFocus;
		}
		+I TestRc { (Match) Break; }
	}
	AnotherFunction { 
		foo;
	}
}

Styles

Styles {
	#This is applied to everything (aka global style)
	MnmButtons;
	MwmBorder;
	MwmDecor;
	SloppyFocus;
	#This affects only RightPanel
	.RightPanel {
		!Title;
		Sticky;
		WindowListSkip;
	}
	#Apply same style to multiple applications (gcolor, gedit, epiphany)
	gcolor3, gedit, epiphany {
		!MwmDecor
	}
	#Apply previous style plus an specific one for gcolor3
	gcolor3 {
		Layer 6;
	}
}

Module Instances

.RightPanel {
	ButtonGeometry 64x64-0+0;
	Colorset 10;
	Columns 1;
	Font "xft:Sans:size=9";
	1x3 { Swallow "FvwmPager" 'FvwmPager 0 3'};
	1x1 { Swallow (NoClose, UseOld) "xclock" 'Exec xclock'};
}

lgsobalvarro avatar Jan 12 '21 20:01 lgsobalvarro

Hi @lgsobalvarro,

Thanks for sending this in -- it's nice to see someone else other than myself has thought about this.

What you're suggesting makes a lot of sense to me. Putting aside any analogies to a CSS or SASS structure, the idea of having configuration blocks, as in:

Style {
   ...
}

Module {
   ...
}

Isn't anything new -- it's how twm has structured its configuration file since the beginning (and fvwm being based on twm would have inherited that before moving away to the line-based syntax we have now).

I certainly don't disagree that moving to a block-based structure might be a good idea. However, I'm also thinking about a few things on top of that:

  • How does this work with external scripting;
  • The config should be parsed but exposed to the end-user easily.

In terms of external scripting, what I'm thinking about here is bringing consistency to the commands which fvwm has -- similar to what tmux does. Indeed, I've referenced this here: (https://github.com/fvwmorg/fvwm3/blob/master/dev-docs/NEW-COMMANDS.md) which I recommend reading. The point is to:

  • Rationalise how we reference desktops/pages/windows, making that consistent.
  • Reduce the sheer amount of duplication we have now between commands and options.

Note that by duplication, I'm referring to styles (affecting windows), and commands which work on windows. There's a lot of overlap between the two which would help to reduce the confusion if there's a consistent means of referring to things like desktops, pages, windows, etc.

We also need to consider whether we need to write our own configuration syntax, or if an existing library would be useful instead. libconfuse seems OK, but there's more power (and hence complexity) in writing our own config syntax via flex/yacc.

I'm sure I'll have more thoughts in due course.

ThomasAdam avatar Jan 17 '21 00:01 ThomasAdam

Thomas Adam [email protected] writes:

Hi @lgsobalvarro,

Thanks for sending this in -- it's nice to see someone else other than myself has thought about this.

What you're suggesting makes a lot of sense to me. Putting aside any analogies to a CSS or SASS structure, the idea of having configuration blocks, as in:

Style { ... }

Note that the current Fvwm accepts commands from multiple sources at the same time. Modules can send commands. They need to be atomic, not multi-line structures.

Back when I started using Fvwm, I came from an TWM variant that used structures. I was happy to get away from that.

-- Dan Espen

danespen avatar Jan 17 '21 00:01 danespen

Hey @danespen,

Note that the current Fvwm accepts commands from multiple sources at the same time. Modules can send commands. They need to be atomic, not multi-line structures.

Indeed -- that's actually a really good point. It's worth remembering that configs aren't static (a point in time) but there are existing commands in fvwm which can send input to other commands. The suggestion from @lgsobalvarro doesn't cover this -- and if fvwm3 ever learned of commands via argc/argb (akin to how cvs works), this would need thinking about quite carefully in terms of how this would fit in with config file, vs sending commands to fvwm3.

@danespen -- isn't what you're referring to the crux of how FvwmAnimate works? I seem to recall that FvwmAnimate can be sent commands to do things -- most notably from FvwmIconMan but I suppose it's not limited to that.

ThomasAdam avatar Jan 17 '21 00:01 ThomasAdam

Back when I started using Fvwm, I came from an TWM variant that used structures. I was happy to get away from that.

@danespen -- I have to ask (as I'm always curious!), aside from Fvwm itself, I wasn't aware of a direct TWM variant at the same time. Do you happen to recall what this was?

ThomasAdam avatar Jan 17 '21 00:01 ThomasAdam

Thomas Adam [email protected] writes:

Back when I started using Fvwm, I came from an TWM variant that used structures. I was happy to get away from that.

@danespen -- I have to ask (as I'm always curious!), aside from Fvwm itself, I wasn't aware of a direct TWM variant at the same time. Do you happen to recall what this was?

There were a bunch. I was using cvtwm. I believe there was also a vtwm (without colored pixmap icons).

-- Dan Espen

danespen avatar Jan 17 '21 01:01 danespen

Thomas Adam [email protected] writes:

Hey @danespen,

Note that the current Fvwm accepts commands from multiple sources at the same time. Modules can send commands. They need to be atomic, not multi-line structures.

Indeed -- that's actually a really good point. It's worth remembering that configs aren't static (a point in time) but there are existing commands in fvwm which can send input to other commands. The suggestion from @lgsobalvarro doesn't cover this -- and if fvwm3 ever learned of commands via argc/argb (akin to how cvs works), this would need thinking about quite carefully in terms of how this would fit in with config file, vs sending commands to fvwm3.

@danespen -- isn't what you're referring to the crux of how FvwmAnimate works? I seem to recall that FvwmAnimate can be sent commands to do things -- most notably from FvwmIconMan but I suppose it's not limited to that.

Yes I believe that was when the issue dawned on me during writing FvwmAnimate.

I forget if FvwmTalk or FvwmForm worried about the issue.

Fvwm has a couple of cases this matters:

When you use a backslash to continue a command, Fvwm could get confused if it got a backslashed command from another source. For that reason, if FvwmTalk wanted backslashes to work it would have to assemble the 2 lines before it sent them.

The other issue is the "+" command that continues functions, etc. I just avoid using the "+" command. Functions are normally defined in the base config file so it's not a serious problem.

It's best to remember, Fvwm takes commands, it doesn't read a configuration.

-- Dan Espen

danespen avatar Jan 17 '21 01:01 danespen

Yes. I have thought of this you mention @danespen.

In fact I was asking myself: How could this I'm proposing work for... let's say... FvwmConsole? I think there could be a way to go about this (from a non-programmer perspective):

  1. Separate commands (quit, restart, read and so on...) from styling. I mean: keep most commands as they are. After all they are straight forward enough.
  2. Being able to use an "atomic" structure, as @danespen suggests for styling in case a module needs to pass it for whatever reason. This atomic structure could be similar to the way inline css works.

Of course this is not a perfect solution. For one it wouldn't be as cleaner as having a complete block syntax config. Still it would simplify styling and probably shorten config files.

Part of my intention with this proposal is to get the conversation going. As @ThomasAdam has point out, there are duplicates (and triplicates?) of commands. This could be a good excuse to start a little cleanup on that area and somehow streamline the config file/process. I myself, find it a bit annoying having to -for instance- define a style for each gnome application I use in order to force it to show proper window decorations, when this could be defined just once and simply list the applications you want to apply this style to.

lgsobalvarro avatar Jan 17 '21 16:01 lgsobalvarro

lgsobalvarro [email protected] writes:

Yes. I have thought of this you mention @danespen.

In fact I was asking myself: How could this I'm proposing work for... let's say... FvwmConsole? I think there could be a way to go about this (from a non-programmer perspective):

1 Separate commands (quit, restart, read and so on...) from styling. I mean: keep most commands as they are. After all they are straight forward enough. 2 Being able to use an "atomic" structure, as @danespen suggests for styling in case a module needs to pass it for whatever reason. This atomic structure could be similar to the way inline css works.

I think you're arguing that styling doesn't have to be done as commands because styling is done once during startup?

If so, I don't think I agree. A styling app would restyle Fvwm interactively. I have one and there are a few others floating around.

Of course this is not a perfect solution. For one it wouldn't be as cleaner as having a complete block syntax config. Still it would simplify styling and probably shorten config files.

Using blocks would be shorter, but I'm not sure I agree about simpler.

What's simpler here:

AddToFunc Warp I Next [$0] Iconify -1

  •      I Next [$0] WarpToWindow 24p 24p
    
  •          I None [$0] Beep
    

or

AddToFunc Warp I Next [$0] Iconify -1 AddToFunc Warp I Next [$0] WarpToWindow 24p 24p AddToFunc Warp I None [$0] Beep

I think the later is simpler because no new operator is introduced.

Part of my intention with this proposal is to get the conversation going. As @ThomasAdam has point out, there are duplicates (and triplicates?) of commands. This could be a good excuse to start a little cleanup on that area and somehow streamline the config file/process. I myself, find it a bit annoying having to -for instance- define a style for each gnome application I use in order to force it to show proper window decorations, when this could be defined just once and simply list the applications you want to apply this style to.

What you proposed looked pretty neat. When I saw it the second time I realized the problem it would create.

If I was trying to improve the command syntax of Fvwm I'd be looking at how Fvwm does parsing. I'd try to make the parsing as table driven as possible. Right now Fvwm uses a lot of functions that aid in parsing, for example, GetNextToken. But those functions are joined up with logic instead of a table.

An example of a table driven parser is the one used for TSO CLISTS. The table names all the keywords and names the variables where the parsed result is put. The table fvwm could use would contain things like this keyword must be followed by a geometry or a color name. It could do things like declare that a keyword must be followed by a number and define the range.

I haven't looked deeply but I suspect that trying to parse commands with tables might force some commands to change syntax.

I've done things like this more than once and it's not easy but it does reduce code size.

-- Dan Espen

danespen avatar Jan 17 '21 18:01 danespen

You are right. It would most likely deeply affect how FvwmCristal, NoCDE and other similar styling utilities work. I just mention it as an example of how what I propose could be convenient to deal with that kind of situations where you'll pass the exact command 5, 10 times just to do something as simple as force gnome apps to honor window decors.

I'm well aware that changing syntax out of the loop and in a radical manner would be problematic, both for developers and users. But as I said, the idea with this post/feature request is to get the conversation going. Get some input of what a new syntax should and should not be/have from both users and developers. Either way the decition of changing the syntax is any way is not mine at all.

What you propose seems like a viable solution, however is out of my league. Could you give us an example of how could it work?

Cheers :)

lgsobalvarro avatar Jan 18 '21 15:01 lgsobalvarro

lgsobalvarro [email protected] writes:

You are right. It would most likely deeply affect how FvwmCristal, NoCDE and other similar styling utilities work. I just mention it as an example of how what I propose could be convenient to deal with that kind of situations where you'll pass the exact command 5, 10 times just to do something as simple as force gnome apps to honor window decors.

I'm well aware that changing syntax out of the loop and in a radical manner would be problematic, both for developers and users. But as I said, the idea with this post/feature request is to get the conversation going. Get some input of what a new syntax should and should not be/have from both users and developers. Either way the decition of changing the syntax is any way is not mine at all.

What you propose seems like a viable solution, however is out of my league. Could you give us an example of how could it work?

I'll use the ClickTime command as an example:

The syntax for that command is

ClickTime Delay

If the Delay is missing it uses DEFAULT_CLICKTIME. Otherwise if the Delay is less than zero, zero is used otherwise the value is converted from a string to an int. The value is stored in Scr.ClickTIme as an int. Then if Fvwm is in startup, the value is changed to a negative value.

So the table entry for parsing that command might be:

int min_params 0 int max_params 1 (For each parameter in this case there is only 1) enum stored_as INT void * stored_where Scr.ClickTIme int int_default_missing DEFAULT_CLICKTIME int min_value 0 int max_value MAX_INT

There would be a pointer in the functable (check functable.h, functable.c) that would point to the above structure.

To support other commands, more things would need to be added. (A lot more things.)

The last part, using a negative value during startup, could be handled with a table entry that says change to negative during startup or by pointing to a unique function to be called after the command is parsed.

The actual function CMD_ClickTime wouldn't be needed. The only thing that might require logic is the special logic for startup. That particular command doesn't do any checking so:

ClickTime Hello

isn't diagnosed. Using a table, I'd expect that it would be since "Hello" is not an int. Probably MAX_INT isn't a good max either. Easier to implement a reasonable max with a table.

-- Dan Espen

danespen avatar Jan 18 '21 17:01 danespen

Hey @danespen,

Yeah, that's certainly one approach. To my mind, an enumeration table makes sense. We could expand this idea more generally though to consider that there are:

  • Global settings which don't work directly on windows at all, so things like:
    • ClickTime
    • DesktopSize
    • etc..
  • Commands which need a window:
    • Style (which would include Decor)
    • Commands to manipulate windows: Move, Resize, etc.
  • Functions (user-defined commands) -- typically require an operand window.
  • Menus
  • Modules (config)

We could generalise the idea that for settings, they operate globally, or per screen or per desktop, or per page, and hence allow for a hierarchical inheritance of this. So for example, take DesktopSize, in FVWM3 this operates at a screen level (so you could say, has a screen context) hence a hypothetical command might be:

  • set -g desktop-size 2 2 -- sets "desktop-size" to 2x2 for all monitors.
  • set -t HDMI1 desktop-size 4 4 -- sets "desktop-size" to 4x4 for just HDMI1, implication is the other attached monitors would therefore use 2 2.

Commands which operate on a window could work similarly:

Move -t :0:XTerm 0 0

Would move the XTerm on the current screen on desktop 0, to position 0 0.

Move 0 0

Would work like Pick Move 0 0 does now, as no window was specified.

If each command was bounded by its understanding of how it is to operate, then we could easily insert defaults in to it upfront. So for example, with ClickTime, we could have an options table which looked like this:

struct options_entry {
    const char *name;
    const char *default_str;
    int default_num;
};

struct options_entry opt_table[] = {
    {
        .name = "ClickTime",
        .default_num = 250;
    }
};

Which means that if the user didn't specify a ClickTime, it defaults to 250. In terms of options, we could just walk the table (as you've said, @danespen), and allow for each option to define its own scope.

I'll get to command/window scoping later on, similar to fvwm's exec_context stuff later...

ThomasAdam avatar Jan 18 '21 23:01 ThomasAdam

Leaving a few more thought here...

I was looking at decors earlier and realised that they're both very powerful and complex, yet utterly incomprehensible.

From the fvwm manpage:

                  AddToDecor FlatDecor
                  + ButtonStyle All Active (-- flat) Inactive (-- flat)
                  + TitleStyle  -- flat
                  + BorderStyle -- HiddenHandles NoInset

If you can tell me at a glance what the end result of that is, you should get commit-bit rights to fvwm3's repository. ;)

I think there's merit to trying to group things together -- I am loathe to go down the Yacc/Bison/Flex route of writing a grammar parser to describe the syntax of a config file. Perhaps using libconfig is easier?

ThomasAdam avatar Jan 27 '21 00:01 ThomasAdam

Thomas Adam [email protected] writes:

Leaving a few more thought here...

I was looking at decors earlier and realised that they're both very powerful and complex, yet utterly incomprehensible.

From the fvwm manpage:

              AddToDecor FlatDecor + ButtonStyle All Active (--
              flat) Inactive (-- flat)

I think active/inactive are for buttons in use or grayed out due to application hints. The all means to apply it to all buttons.

              + TitleStyle -- flat

Not sure what a flat titlestyle is maybe no shadows.

              + BorderStyle -- HiddenHandles NoInset

The handles separate the border from the corners of the border. THere's an inset for the separation?

If you can tell me at a glance what the end result of that is, you should get commit-bit rights to fvwm3's repository. ;)

Well, that's my glance.

I think there's merit to trying to group things together -- I am loathe to go down the Yacc/Bison/Flex route of writing a grammar parser to describe the syntax of a config file. Perhaps using libconfig is easier?

Not sure what you're getting at.

All that decoration stuff was done before I got involved so I don't know any history on it.

-- Dan Espen

danespen avatar Jan 27 '21 00:01 danespen

Hi @danespen

Yeah -- the decor syntax is really confusing. I've only ever had to use it to change a few things, as I stick to the MWM-style of window decorations anyway.

My point about Yacc/Bison was to highlight that we have a choice of either defining our own syntax for the proposal that @lgsobalvarro has suggested, or we look at existing configuration libraries, such as libconfig. Given the frustrations I've had with how fvwm does its syntax parsing, I'm keen to avoid too much rework of writing our own config file format using yacc. But I need to give it some more thought.

ThomasAdam avatar Jan 27 '21 00:01 ThomasAdam

Thomas Adam [email protected] writes:

Hi @danespen

Yeah -- the decor syntax is really confusing. I've only ever had to use it to change a few things, as I stick to the MWM-style of window decorations anyway.

My point about Yacc/Bison was to highlight that we have a choice of either defining our own syntax for the proposal that @lgsobalvarro has suggested, or we look at existing configuration libraries, such as libconfig. Given the frustrations I've had with how fvwm does its syntax parsing, I'm keen to avoid too much rework of writing our own config file format using yacc. But I need to give it some more thought.

Ah, I see.

I've always done hand crafted parsers. More fun.

So far I haven't seen any syntax changes that appealed to me, but then I don't really want to make changes to my config anyway.

-- Dan Espen

danespen avatar Jan 27 '21 00:01 danespen

I joke about this on IRC yesterday night. Here is my "official" answer.

              + ButtonStyle All Active (-- flat) Inactive (-- flat)

Flattens button style when buttons are active and/or inactive.

              + TitleStyle  -- flat

Flattens Titlebar. No idea what exactly "flats" here.

              + BorderStyle -- HiddenHandles NoInset

Hides Handles?

I don't know. I have always used the MWM decor. So I have not really played with window decors. And without trying this out, I can't really tell what it does exactly.

lgsobalvarro avatar Jan 27 '21 15:01 lgsobalvarro

I think what I'd like to see is a preprocessor approach to a new syntax, similar (but not in implementation) to what FvwmPerl does now.

For example, using lua, we could write a preprocessor for syntax which defined a config structure for:

style <...> {
    ...
}

function <...> {
    I {
        ....
    }
    C {
        ....
    }
}

etc...

... which then converts that to current fvwm syntax, sending it to fvwm dynamically (via FvwmMFL).

This would allow us to work on this independently of any deeper changes to Fvwm until we're happy with it.

ThomasAdam avatar Jan 31 '21 01:01 ThomasAdam

I don’t love lua (no strong opinion here yet), but I do like the approach you outlined @ThomasAdam.

codedmart avatar Jan 31 '21 15:01 codedmart

It will be transparent to the user. It's not about forcing lua on people, this is the language choice for writing the preprocessor in for whatever DSL sort of thing we create. This has always been FVWM's approach; it's always had a DSL of sorts. Lua sounds reasonable as it has hooks in C, but also we could expand this for hook-support in the future.

ThomasAdam avatar Jan 31 '21 15:01 ThomasAdam

I think what I'd like to see is a preprocessor approach to a new syntax, similar (but not in implementation) to what FvwmPerl does now.

For example, using lua, we could write a preprocessor for syntax which defined a config structure for:

style <...> {
    ...
}

function <...> {
    I {
        ....
    }
    C {
        ....
    }
}

etc...

... which then converts that to current fvwm syntax, sending it to fvwm dynamically (via FvwmMFL).

This would allow us to work on this independently of any deeper changes to Fvwm until we're happy with it.

I think this is a really good idea. This approach would allow us to develop a new syntax in an "independent" way to any changes made to FVWM core, as you point out. Also it would allow to the new syntax evolve accordingly to feedback and user needs without the need of doing major changes to FVWM. Or so I gather from your comments.

lgsobalvarro avatar Feb 01 '21 15:02 lgsobalvarro

lgsobalvarro [email protected] writes:

I think what I'd like to see is a preprocessor approach to a new syntax, similar (but not in implementation) to what FvwmPerl does now.

For example, using lua, we could write a preprocessor for syntax which defined a config structure for:

style <...> { ... }

function <...> { I { .... } C { .... } }

etc...

... which then converts that to current fvwm syntax, sending it to fvwm dynamically (via FvwmMFL).

This would allow us to work on this independently of any deeper changes to Fvwm until we're happy with it.

I think this is a really good idea. This approach would allow us to develop a new syntax in an "independent" way to any changes made to FVWM core, as you point out. Also it would allow to the new syntax evolve accordingly to feedback and user needs without the need of doing major changes to FVWM. Or so I gather from your comments.

I'm missing the value of it. How does it help users to give them 2 different syntaxes to deal with?

Is the new syntax easier to learn or understand, does it help to write configuration GUIs?

-- Dan Espen

danespen avatar Feb 01 '21 15:02 danespen

I'm missing the value of it. How does it help users to give them 2 different syntaxes to deal with? Is the new syntax easier to learn or understand, does it help to write configuration GUIs?

For what I gather, and @ThomasAdam can correct me if I'm wrong, it would be just one syntax the user would use. The other one (the current one) would be for FVWM "internal use".

I think what I proposed initially would be easier to learn and understand, if as a user you are at least a bit familiar with css or any similar markup that relays on blocks/brackets.

lgsobalvarro avatar Feb 01 '21 15:02 lgsobalvarro

For what I gather, and @ThomasAdam can correct me if I'm wrong, it would be just one syntax the user would use. The other one (the current one) would be for FVWM "internal use".

This reminds me an awful lot of LISP S-Expressions and M-Expressions. That's not a terrible thing, but I just never see any dialects of LISP that really use M-Expressions these days (everyone basically settled on S-Expressions).

I think what I proposed initially would be easier to learn and understand, if as a user you are at least a bit familiar with css or any similar markup that relays on blocks/brackets.

My thoughts after reading through these comments:

I'd like to see it done as a translation into the internal syntax, if possible. For instance, if functions are declared like this

    # function definition
    do_a_thing() {
        command
    }

…That can be converted to the DestroyFunc do_a_thing/AddToFunc do_a_thing/+ syntax relatively easily by just listening for a closing curly brace with a stack. It also is reminiscent of shell scripts, which is an upshot in my opinion due to the high amount of use bourne shell scripts get in Unix environments. The () acts as a keyword to let the parser know that what follows will be a function definition.

If we want other kinds of "structured" data, either another kind of token could be used ([] for instance), or perhaps instead of using such tokens we could simply do something like what bash can optionally use for declaring functions:

function name [()] compound-command

…With function being the keyword for adding a function, and style being the keyword for adding styling information, for instance. A style keyword would then be parsed into a bunch of Style commands (or comma-separated values and a single Style command) until the closing } was reached.

This has the upshot of being more legible/less cryptic at a glance than, say, square brackets, at least to an average user of C-inspired languages or bash scripts (note that traditional bourne shell has no function builtin; this is a bash-ism. Bourne shell only specifies the func_name() {command} syntax).

For styles, therefore:

style xclock {
    Sticky
    !Title
    !Borders
    StaysOnTop
}
style * {
    Font "StringEncoding=UTF-8:xft:MS UI Gothic:size=9:bold:antialias=false,xft:Tahoma:size=8:bold:antialias=false"
}

…Would be equivalent to (and be decoded to) the traditional notation as either:

Style "xclock" Sticky
Style "xclock" !Title
Style "xclock" !Borders
Style "xclock" StaysOnTop

Style * Font "StringEncoding=UTF-8:xft:MS UI Gothic:size=9:bold:antialias=false,xft:Tahoma:size=8:bold:antialias=false"

Or, even better, simplified with commas to:

Style "xclock" Sticky, !Title, !Borders, StaysOnTop
Style * Font "StringEncoding=UTF-8:xft:MS UI Gothic:size=9:bold:antialias=false,xft:Tahoma:size=8:bold:antialias=false"

With the comma separation, we'd likely want to limit the length of individual lines to aid in debugging; for debugging purposes, the former translation might be better (and would certainly be easier to write). And with this notation, we could write functions as:

function FunctionName {
    +I Action
}

Translating to:

DestroyFunc FunctionName
AddToFunc FunctionName
+ I Action

…Perhaps this could be loaded from a separate "resource" file from the main FVWM config file by use of a new command (maybe called Parse, LoadResource, or ImportStructured? Just ideas; there's probably a better name out there, but this is a stream of consciousness post so I hope it makes sense/is coherent). The main upshot of the new format would be legibility at the cost of lower flexibility, which should rightly be a choice for the user to make. If desired, the user could simply have a one-line .fvwmrc/~/.fvwm/config file containing LoadResource $[FVWM_USERDIR]/structured-config. Of course, this way, using the traditional syntax it would still be possible to do additional AddToFunc's and similar as needed (or AddToFunc could be called from within the new format since it's translated when it's parsed). Alternatively a secondary keyword called append could be used which causes the parser to not generate the DestroyFunc line when followed with the function keyword.

I hope this was coherent and didn't ramble to much. I wrote it as I thought of things. Basically I think a shell-like syntax might be easier and also closer to the internal representation FVWM uses while retaining some benefits for end users in terms of the readability of things.

wyatt8740 avatar Feb 07 '21 18:02 wyatt8740

Wyatt Ward [email protected] writes:

For what I gather, and @ThomasAdam can correct me if I'm wrong, it would be just one syntax the user would use. The other one (the current one) would be for FVWM "internal use".

Yagg!

Think about it.

Are you going to duplicate all of Fvwm's internal error checking? If not, the user types one thing, Fvwm responds with an error message about some generated command nothing like what the user entered.

It's madness I tell you!

-- Dan Espen

danespen avatar Feb 07 '21 18:02 danespen

Ah, that is fair. I didn't even think about how errors would be handled with this system. I'd probably have to have it be reversible, in that case… or have some automatically generated comments on the ends of lines that correlate them to the structured format line numbers.

Edit: Actually, upon reflection, didn't I basically just describe the kind of thing a C preprocessor would do? Maybe i should see how C compiler errors sourced from header file includes get traced back.

I suppose one could also add a way to tell fvwm to parse the config and print the result, including all parsed/sourced definitions, although that would still be like debugging at a different level than the source code (in an intermediary language).

Thanks for the input; this was basically an RFC (in the literal "request for comments" sense; just to get feedback) from me, anyway.

wyatt8740 avatar Feb 07 '21 19:02 wyatt8740

Wyatt Ward [email protected] writes:

Ah, that is fair. I didn't even think about how errors would be handled with this system. I'd probably have to have it be reversible, in that case… or have some automatically generated comments on the ends of lines that correlate them to the structured format line numbers.

Well, took me a while to connect the dots.

First time I saw someone implement something like that was some time in the 70s. Never let the back end do edits.

cpp barely pulls it off. Many the time I had to examine the cpp output to understand where compiler errors were coming from.

I think Fvwm is stuck with processing commands (as it should be).

-- Dan Espen

danespen avatar Feb 07 '21 19:02 danespen

I think Fvwm is stuck with processing commands (as it should be). I'd be happy with leaving it alone and unchanged as well; I mainly wrote that up as a thought exercise. I have no (large) issues with how FVWM configuration currently works, since I am happy with how my desktop currently behaves.

I suppose that such a program would be easily implementable by the user, anyway, and might just be extra bloat and maintenance burden to include in the core functionality of FVWM.

Many the time I had to examine the cpp output to understand where compiler errors were coming from.

I edited my message and alluded to that as well… since I believe you're using email notifications, I'll quote it.

Edit: Actually, upon reflection, didn't I basically just describe the kind of thing a C preprocessor would do? Maybe i should see how C compiler errors sourced from header file includes get traced back. I suppose one could also add a way to tell fvwm to parse the config and print the result, including all parsed/sourced definitions, although that would still be like debugging at a different level than the "source code" (in effectively an intermediate language).

I 100% understand where you're coming from; I'm not convinced it's a good idea either, just potentially less disruptive than some of the other syntaxes people have mentioned in this issue since the actual FVWM command syntax would not need to change.

wyatt8740 avatar Feb 07 '21 19:02 wyatt8740

On the danger of coming late to the party, and maybe missing something here:

I think there's merit to trying to group things together -- I am loathe to go down the Yacc/Bison/Flex route of writing a grammar parser to describe the syntax of a config file. Perhaps using libconfig is easier?

Maybe JSON would be an option? It is at least marginally human-readable, can hold nested data structures and can be used with or converted from a lot of formats and languages. (e.x. when I write python programs, I have all my settings in a dict, which I can simply push out into a JSON-file and be done with it, and read it in the same way, no grammar parsing required). Not knowing how FVWM handles it's config this might be an easy / accessible solution.

dwrl avatar Mar 05 '21 01:03 dwrl

Maybe JSON would be an option?

No thanks. It's not very extensible, would become unweildy, and the JSON specification doesn't allow for comments.

ThomasAdam avatar Mar 05 '21 18:03 ThomasAdam

Hm, sorry. I did not intend to write that much... But I'm really trying to get to a point in the end!

Aaaah, what syntax? A questinon that provides fertile grounds for disputes of religious dimensions. Good luck with that ;-)

No, honestly: I'm happy to see FVWM3 getting a DSL for configuration, and I sincerely believe this is a good idea. And a difficult task.

Let me elaborate:

All languages are crap, at some point at least. This can be easily verified by observing how many languages there are — if there was a really good one, then everybody would use it. But people are not happy with the languages they have, so they invent new ones. Even within a single use case (querying, programming), people cannot agree on a language.

And configuration? Well, none of the available languages seems to cut the mustard for FVWM3.

Don't use XML, nor JSON

Having worked on XML professionally (implemented Schema validation, built an XQuery compiler), I've got a pretty stong opinion about XML: It is pure shite. Overengineered and overly complex. Just try to read the entire standards body.

But there's one thing about XML that I want to point out, which distinguishes it from languages like JSON: XML allows to introduce new, named constructors. I'll explain what I mean by that.

At an abstract level, most languages (and all I'd consider relevant here) represent something with the structure of a rooted tree, or a directed acyclic graph.

Primitives are the nodes that have no outgoing edges, they are not constructed from other things. In C, an integer literal would be such a thing

42

or a variable

x

Then, each language provides means to construct new things from these primitives. In C, you can build an assignment

x = 42;

JSON also provides primitives (numbers, strings, …) and means to construct new things, like an object

{ "x": 42 }

But the things you can build in JSON are limited, it's lists and objects. Nothing more. Whether two objects are the same depends only on the members of the object. Contrast this with XML, where tags act as constructors:

<meter>42</meter>

<foot>42</foot>

This could represent two different objects, each constructed from (its own instance of) the same primitive 42, by using different constructors, meter and foot. And you can have any number of these constructors. In JSON? No can do. One might try

{ "unit": "meter", "value": 42 }

which is something different: It's just an object with two members. To be recognised as a length, a convention is required, like to look for a unit and a value member. When validated by a consumer, and transformed into something representing “42 meters”, then a reconstruction of a different datastructure has taken place. (And yes, not having comments in JSON is a major pain in the back.)

Being able to define and name constructors does not only allow to distinguish things which are identical on the inside. It also allows to create identical things in different ways, just think of Java classes having different constructors, like

Date(int year, int month, int date)
Date(long millisecondsSinceEpoch)
Date(String s)

which, as a side note, do have different names, because the signature is kinda part of the naming. Unfortunately.

I'd really hope that FVWM3's configuration would provide named constructors. I'll come back to that...

What I'd like to see in a config language

With the following list, one may wonder whether I'm not striving for a fully fledged programming language. And rightly so. It boils down to the question what we consider configuration. This is another issue of much debate.

  • Primitives: Numbers, booleans and strings.

  • Constructors to build simple generic data structures, like heterogeneous lists. This could be a syntax using brackets, like [1, 2, 3].

  • Constructors to build objects special to the domain, for a window manager these might be menus and their items, colors, fonts, keypress identifiers, and what not.

  • A strict, static type system that is strong enough to reject an invalid configuration instead of yielding a runtime error.

  • Variables, so that I can define a color once and use it many times.

  • Abstraction, so that I can construct similar things easily.

  • Evaluation of expressions, so that I can concatenate path names, or calculate some arithmetic expression.

  • A very simple, compact and elegant syntax. Really have a look at Haskell for that.

An intermediate language

Having an “imtermediate” or “core” config language, as has been suggested, is certainly politically smart, because it does not slam the door in the face of anyone who does not like it (but in the end, most people will not like the config language anyways, see above).

It may not even be as insane as it looks at first: Many compilers use an intermediate representation to compile the input language to.

Of course, each compiler frontend does all the checking it can do, trying hard not to produce a flawed intermediate representation (which produces awkward error messages when it happens). But this is likely the only way to do it, some errors may not even be practial to find in some representations.

But the reason to use intermediate representations is rather technical, than political: When different language features may be expressed by the same means of a core language, then “desugaring” makes writing a compiler easier. E.g., in C we can replace

a[i]   ↦   *(a + i)

or in Haskell, where the entire construct of list comprehension can be removed from the syntax

  [ x + 1 | x <- [1..100], even x ]
↦
  concatMap (\x -> if (even x) then [x + 1] else []) [1..100]

Also, intermediate languages should be crafted in a way to make desirable operations easier, or to expose properties not easily accessible in the surface language.

What does this mean here?

An intermediate configuration language should not be crafted to be very easy to read, but rather to be minimal in the number of means it provides, and close to the structures iniside FVWM3 that need to be controlled. This could be extremely simple plain text reverse polish notation (RPN) which lends itself nicely to build trees and DAGs. Or less simple RPN, as in PostScript. But it could also be something more standardised, like ASN.1 or Protocol Buffers (both of which I've never used).

But in any case, this intermediate language should be really well designed, i.e., it must be able to express all configuration needs that FVWM3 has, be it commands, or description of styles or menus, and what not.

Which brings me to the final point:

First, define an API

I think it would be helpful to have a very clear picture of what the config language should be able to express. Formal, detailed and precise. So much so, that it is basically an API.

This API must be the only interface to configure FVWM3.

Thus, FVWM3 being written in C, C would also be FVWM3's first prototypical configuration language.

The functions, values and types provided by this API represent the constructors and primitives mentioned above. C adds its means of abstration and combination, and a simple type system.

If time proves the API stable, and simple, and elegant enough, it would become clear what features a config language should provide.

If the API is clean and complete, in the sense that everything that FVWM3 must be able to digest can be fed in through that API conveniently, then designing a suitable surface language should follow naturally, I hope.

Any disputes about syntax should be postponed until then.

The plan would be to consider the API the intermediate language, but instead of compiling a configuration DSL into C code, the DSL would be interpreted into API calls.

I cannot tell what the result will be. Maybe it turns out to be Lua (God help us), or a Python library that feeds ASN.1 into FVWM3 via a socket, or a nice DSL like the one for FVWM2, which has proven very usable for me.

s5k6 avatar Apr 10 '21 11:04 s5k6