Skip to content

This issue was moved to a discussion.

You can continue the conversation there. Go to discussion →

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Collecting possible formatting styles #23

Closed
kenkangxgwe opened this issue Feb 7, 2020 · 7 comments
Closed

Collecting possible formatting styles #23

kenkangxgwe opened this issue Feb 7, 2020 · 7 comments
Labels
collection This contains a collection of feedback help needed Extra attention is needed long-run Works that will be done in the unforeseen future

Comments

@kenkangxgwe
Copy link
Owner

This issue is to collect different formatting styles of Wolfram Language. The current state of the language server is not capable to do complicate formatting (not even simple ones, because I haven't implemented any lol). I know that Brenton (@bostick the author of AST and Lint) is working on a code formatter (see the end of the video, and I definitely admire his ambition to do notebook manipulation 🤣 but I haven't known whether his formatter will let users define their own styles.

Since people have different appetites this issue welcomes ALL possible styles that we can format the wolfram language into. YES, all possible styles. I didn't say I would accept or implement all of them, just for the aesthetic purpose.

A code block or screenshot to illustrate the style is recommended.

Here are some features we can start thinking from:

indentation

  • indentation character: Tab vs
  • indetation width
    • constant integer: 2, 4, etc.
    • adjust it according to context
      • Align it with other parameters in the function call
        If[condition,
            true,
            false
        ]

whitespaces

  • whitespaces for between operators:
    • F@a vs F @ a same for (//)
    • a ~Join~ b vs a ~ Join ~ b
    • i++ vs i ++ same for other unary operators
    • "str"<>"ing" vs "str" <> "ing" (same for ~~)

empty lines

  • top-level expressions
    Adding two lines will make a separate cell for the code block if you open the
    .wl/.wls file in Mathematica. Thus it is recommended to split up different
    Functions into cells.
    (* ::Section:: *)
    (*section name*)
    
    
    Function1 := functionDefinition1
    
    
    Attributes[Function] = {Protect}
    (* overloads *)
    Function2[a_String] := (functionDefinition2)
    Function2[a_] := (functionDefinition3)
    vs keep it as it is

line wrapping

  • Wrap a long line (exceeds 80 chars for example)
    first parameter dangling if it doesn't exceeds 80 chars after wrapping
    Function[aVeryLongParameterThatSomeHowYouWantToWrapTheLine1,
              aVeryLongParameterThatSomeHowYouWantToWrapTheLine2]
    vs always wrap the parameters.
    Function[
        aVeryLongParameterThatSomeHowYouWantToWrapTheLine1,
        aVeryLongParameterThatSomeHowYouWantToWrapTheLine2]
  • Which function to wrap when a line is too long
    wrap from the end of the line
    ThisFunctionHasALongName[ThisFunctionHasALongNameToo[
        ThisParameterHasLongNameToo]]
    vs wrap from the start of the line
    ThisFunctionHasALongName[
        ThisFunctionHasALongNameToo[ThisParameterHasLongNameToo]
    ]

dangling operator / delimiter

  • put ] at the end of the line
    Function[aVeryLongParameterThatSomeHowYouWantToWrapTheLine1,
              aVeryLongParameterThatSomeHowYouWantToWrapTheLine2]
    vs put ] at the begining of the line
    (*dynamic indentation*)
    Function[
              aVeryLongParameterThatSomeHowYouWantToWrapTheLine1,
              aVeryLongParameterThatSomeHowYouWantToWrapTheLine2
    ]
  • put {, (, <| at the end of the line
    list = {
        aVeryLongListElement1,
        aVeryLongListElement2,
        aVeryLongListElement3
    }
    vs always begin a new line
    list =
    {
        aVeryLongListElement1,
        aVeryLongListElement2,
        aVeryLongListElement3
    }
  • put binary operators at the end of the lines
    MatchQ[form1 |
            form2 |
            form3]
    vs put binary operators at the beginning of the lines
    MatchQ[form1
            | form2
            | form3]
    same for &&, ||, <>, ~~, etc

semi-colon (so called CompoundExpression)

  • Auto remove semi-colons at the end of the top-level expressions
  • Keep it as it is
  • Auto-add semi-colons at the end of the top-level expressions (highly unrecommended)
@kenkangxgwe kenkangxgwe added help needed Extra attention is needed collection This contains a collection of feedback long-run Works that will be done in the unforeseen future labels Feb 7, 2020
@kenkangxgwe kenkangxgwe pinned this issue Feb 7, 2020
@asukaminato0721
Copy link

well, I have a little idea: Maybe we can look for format from ready-made MMA code.
Two ways:

  1. Since IntelliJ already has a complete mma plugin(But very heavy). link. Maybe something can learn from it?

  2. Since code from mse is very scattered. So we can pick some code from Github. for example, Galaster's , The plugin itself.

Actually I do put this link to mma QQ group, maybe they doesn't notice?

@asukaminato0721
Copy link

I accidently find this:
https://www.zhihu.com/question/24090511/answer/1080199503
in which it says:

GU`FM = NotebookPut[
    Notebook[
        {GeneralUtilities`MakeFormattedBoxes@#}
    , StyleDefinitions -> GeneralUtilities`Debugging`PackagePrivate`$DefinitionNotebookStyleDefinitions]
]&;
SetAttributes[GU`FM, HoldAllComplete]

This is a built-in formatter XD.

@asdasd1dsadsa
Copy link

asdasd1dsadsa commented Mar 23, 2020

I accidently find this:
https://www.zhihu.com/question/24090511/answer/1080199503
in which it says:

GU`FM = NotebookPut[
    Notebook[
        {GeneralUtilities`MakeFormattedBoxes@#}
    , StyleDefinitions -> GeneralUtilities`Debugging`PackagePrivate`$DefinitionNotebookStyleDefinitions]
]&;
SetAttributes[GU`FM, HoldAllComplete]

This is a built-in formatter XD.

GeneralUtilities`MakeFormattedBoxes returns nested RowBox of string lists. To convert the formatted expression to a string, just ReplaceAll RowBox by StringJoin.

This can be a temporarily method that does not look bad.

@asdasd1dsadsa
Copy link

asdasd1dsadsa commented Mar 23, 2020

My style of formatting

indentation

tab

whitespaces

It usually depends on the precedence of the operators compared to their neighbour.
Mostly:

f@x
x //f
a~Join~b
f @@ x
f /@ x
i++
"str"<>"ing"
a*b + c/d
<|a -> b|>
l[[1]]
l[[ ;;-2 ]]
a&&b || c&&d
f[a, b]&@c
f[manyThings] &@b
f[manyThings]& @@ b

empty lines

For the definition related to the same symbol, one lines between them. Otherwise, two lines.

For logically different/independent definitions, they will be in different cell groups.

line wrapping

For not only very long expressions, but also many expressions (such as If[...]) which is not too short, I will wrap it like this:

Switch[x,
    a, b
    c,
        veryLongdddddddd
]

For nested long expression, I will break the outer one:

longfffffffunction[
	anotherlonggggg[args]
]

dangling operator / delimiter

When the last argument is long, I never put ] behind it, unless it's an unimportant option.

f[
	long,
	anotherLong
]

g[
	longArg
, longOption]

When it's an operator before the bracket, usually no line-break.

short = {
    long1,
	long2
}

anyHeadNoMatterShortOrLong@{
    long1,
	long2
}

When it's a bracket:

short[{
    long1,
	long2
},
, option1
, option2
]

longggggggggggg[
	{
    	long1,
		long2
	},
	someArgs(* If there isn't any argument, I will write prefix-type code. *)
]

put binary operators at the end of the lines

Never. It may mislead the understanding of precedences.

If it's too long, I will use the normal expression form instead of the operator.

MatchQ@Alternative[
	longForm1,
	longForm2
]

Alternatively, I sometimes define a new variable or use With

With[
	{form1 = veryLongFormDefinition},
	MatchQ[form1 | form2]
]

semi-colon (so called CompoundExpression)

Keep it as it is.

@kenkangxgwe
Copy link
Owner Author

kenkangxgwe commented Mar 24, 2020

GeneralUtilities`MakeFormattedBoxes returns nested RowBox of string lists. To convert the formatted expression to a string, just ReplaceAll RowBox by StringJoin.

This can be a temporarily method that does not look bad.

I found it not suitable for users like me who expect the formatter to do its least work to damage the code structure, because,

  1. It changes the postfix and infix form to prefix: f[x], x // f -> f @x
  2. It adds parentheses to expression: 1*2 + 3 -> (1 * 2) + 3
  3. It changes lambda to its full name: f[a; #] & ->
    Function[
    	Global`f[
    		Global`a;
    		#
    	]
    ]
  4. You see it exposes the context name before the variable. 🤣

@kenkangxgwe
Copy link
Owner Author

I would like to give users the freedom to customize their format flavor, by importing a set of rules written by yourself. But for now, I think I can start by implementing the indentation and empty lines, which seems easier.

@asukaminato0721
Copy link

Any progress? 👀

Repository owner locked and limited conversation to collaborators Aug 9, 2022
@kenkangxgwe kenkangxgwe converted this issue into discussion #70 Aug 9, 2022

This issue was moved to a discussion.

You can continue the conversation there. Go to discussion →

Labels
collection This contains a collection of feedback help needed Extra attention is needed long-run Works that will be done in the unforeseen future
Projects
None yet
Development

No branches or pull requests

3 participants