Skip to content
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

Request to vertically align code blocks via various characters #157

Open
adrifoster opened this issue Aug 24, 2023 · 3 comments
Open

Request to vertically align code blocks via various characters #157

adrifoster opened this issue Aug 24, 2023 · 3 comments

Comments

@adrifoster
Copy link

It would be great to have a way to programmatically vertically align code.

e.g.:

this:

  logical, intent(in) :: doalb       ! true if time for surface albedo calc
  real(r8), intent(in) :: nextsw_cday ! calendar day for nstep+1
  real(r8), intent(in) :: declinp1    ! declination angle for next time step
  real(r8), intent(in) :: declin      ! declination angle for current time step
  logical, intent(in) :: rstwr       ! true => write restart file this step
  logical, intent(in) :: nlend       ! true => end of run on this step
  character(len=*), intent(in) :: rdate       ! restart file time stamp for name

would become this:

  logical,          intent(in) :: doalb       ! true if time for surface albedo calc
  real(r8),         intent(in) :: nextsw_cday ! calendar day for nstep+1
  real(r8),         intent(in) :: declinp1    ! declination angle for next time step
  real(r8),         intent(in) :: declin      ! declination angle for current time step
  logical,          intent(in) :: rstwr       ! true => write restart file this step
  logical,          intent(in) :: nlend       ! true => end of run on this step
  character(len=*), intent(in) :: rdate       ! restart file time stamp for name

Is this possible?

@nbehrnd
Copy link

nbehrnd commented Sep 1, 2023

@adrifoster Based on your GitHub profile, I assume you have both access and familiarity with Python and Jupyter notebooks because the approach below is set for copy-paste into a cell of the later.

Conceptually, it reads the strings and splits them on defined keywords; it is naïve as in «(hopefully) easy to understand, while terribly inefficient» because each iteration of adjustment / padding the entries, every line is read twice: once to determine the maximal width in this «column», then to eventually adjust this column. I'm fine if you or/and an other provides a more efficient solution than this zeroth generation doodle:

def split_mechanism(raw_data = "", keyword = ""):
    """provide lines padded up to, yet excluding a particular keyword"""
    length_longest_fragment = 0
    adjusted_lines = []

    # the determination of the longest snippet length:
    for line in raw_data:

        length = len( str(line.split(keyword)[0]).strip() )
        if length > length_longest_fragment:
            length_longest_fragment = length

    for line in raw_data:
        # empty lines are not of our interest here:
        if len(line) == 0:
            continue

        padded_snippet = f"{line.split(keyword)[0].strip():{length_longest_fragment + 1}}"
        output = "".join([padded_snippet, keyword, line.split(keyword)[1]]) 
        adjusted_lines.append(output)

    return adjusted_lines


raw="""
logical, intent(in) :: doalb       ! true if time for surface albedo calc
real(r8), intent(in) :: nextsw_cday               ! calendar day for nstep+1
real(r8), intent(in) :: declinp1    ! declination angle for next time step
real(r8), intent(in) :: declin      ! declination angle for current time step
logical, intent(in) :: rstwr       ! true => write restart file this step
logical, intent(in) :: nlend       ! true => end of run on this step
character(len=*), intent(in out) :: rdate       ! restart file time stamp for name
"""

lines = raw.split("\n")

up_to_intent = split_mechanism(raw_data = lines, keyword = "intent")
up_to_double_colon = split_mechanism(raw_data = up_to_intent, keyword = "::")
up_to_comment = split_mechanism(raw_data = up_to_double_colon, keyword = "!")

for line in up_to_comment:
    print(line)

The input in the example differs twice from the example shared by you. In the second line, there is some additional white space. This aims to replicate situations when comments, attributes, variables etc. get removed / reorganized into other lines while assembling the source code. The white space is trimmed off to close the gaps; for easier reading of the next block however amended by one trailing single position. For instances of intent(out), or intent(in out) in lieu of intent(in), the last line of the input was edited accordingly.

With Python 3.11.5 / IPython 8.14.0 and Jupyter 6.4.12, the output of the cell above is

logical,          intent(in)     :: doalb       ! true if time for surface albedo calc
real(r8),         intent(in)     :: nextsw_cday ! calendar day for nstep+1
real(r8),         intent(in)     :: declinp1    ! declination angle for next time step
real(r8),         intent(in)     :: declin      ! declination angle for current time step
logical,          intent(in)     :: rstwr       ! true => write restart file this step
logical,          intent(in)     :: nlend       ! true => end of run on this step
character(len=*), intent(in out) :: rdate       ! restart file time stamp for name

which seems to provide the help intended.

Question to you: Out of curiosity, can you please indicate an example of this extended formatting? Part of the reason to write the slit_mechanism this way and its sequential calls is I sometimes encounter alignment in the declarations around :: only (independent of single spaces trailing/not trailing comma, single colon, etc.).

@adrifoster
Copy link
Author

This is great thank you! In terms of an extended example... perhaps see this? https://github.com/ESCOMP/CTSM/blob/1e2e2c35d9568c94eac6cb606f37c18294158682/src/main/LandunitType.F90#L28 I agree that often the alignment is done in completely different ways, and I'm not sure what is the best.

@nbehrnd
Copy link

nbehrnd commented Sep 8, 2023

@adrifoster Thank you for indicating an example. As for a consistent format in Fortran in general, I'm not aware if there are recommendations this much formalized and frequently adopted as e.g., around PEP8 (and then checked / applied e.g., by flake8, pylint; black, yapf3, ruff) for Python.

Do not forget to protect the adjusted block, for example with a fence similar to

!&<
logical,          intent(in)     :: nlend       ! true => end of run on this step
character(len=*), intent(in out) :: rdate       ! restart file time stamp for name
!&>

Else, the next run of fprettify with its defaults (or an explicit style as defined in a style file indicated by -c, an example mentioned in a pending PR) is going to overwrite (and alter) it again.

nbehrnd added a commit to vmagnin/ForSudoku that referenced this issue Sep 12, 2023
For easier reading of git's reflogs and diff views, some lines
were manually edited/truncated.  The test and reference arrays
in check.f90 were protected by "fprettify fences" to retain some
visual guide; the additional white space does not affect the
result of fpm test, nor the diff test launched by the Makefile.
For the present project, with editors with syntax highlighting,
I'm not sure if an horizontal alignment of variable declarations
(and not only around `::`, as discussed on fprettify[1]) is of
significant advantage here.

[1] fortran-lang/fprettify#157

Signed-off-by: Norwid Behrnd <[email protected]>
nbehrnd added a commit to vmagnin/ForSudoku that referenced this issue Sep 19, 2023
This commit combines the application of the fprettify rule
based reformat with additional manual edits (truncation of
long lines, etc.) to eventually ease reading of git's reflogs
and diff views.
Reference arrays in check.f90 were protected by "fprettify
fences" to retain some visual guide which does not affect the
result of fpm test, nor the diff test launched by the Makefile.
For the present project, with editors with syntax highlighting,
I'm not sure if an horizontal alignment of variable declarations
(and not only around `::`, as discussed on fprettify[1]) is of
significant advantage here.

[1] fortran-lang/fprettify#157

Signed-off-by: Norwid Behrnd <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants