Make this code explanation pretty again

LiveScript, 243 236 233 228 219 225 bytes

f = (x,k,m+5)->l=(.length);x.=map(->it/"#k"=>..0-=/ +$/;m>?=5+l ..0);i=0;[..0&&..0+' '*(m- l ..0)+k+..1 for x]=>while i<(l ..),++i=>j=(s=..[i])lastIndexOf ' ' 93;(..splice i+1 0 ' '*m+k+s[j to]*'';s.=substr 0 j) if 94<l s;..[i]=s

How it works: mostly like the Java code. Start off by aliasing length (LiveScript allows to create a function from operators by using parentheses). .= is a = a.b - which we use here to map.

=> blabla .. is the Smalltalk-ish cascade construct: the left side of => is accessible as .. for the rest of the block; and will be returned. Here, it's the element split on k. Note: I'm using string interpolation, because / only means "split" with a literal string.

LS allows us to use a-=/regexp/ in this lambda as well (also works with string literals): it's just sugar for a .replace call.

Finally, the >?= is the combinatory >?-assign operator, which returns the greater of two operands.

LS has Python/Haskell-style for comprehensions, with nothing fancy in them, except the "string * times" to repeat the space long enough.

This for comprehension serves as the topic (see the block about cascades anove).

We then loop into each element of the array (the one we just built with the comprehension), and if any line is bigger than 93chars, we find the last index of , split there, and push the separated line right after this current iteration's (... So that the next iteration will split again if the line's too big).

Only last thing fancy a[j to] is a range (from j to the end), but since it uses Array methods we have to join it back to a string, which we do using overloaded *: *''.

example

s = """this is kod # Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
d # y

efgh # z"""

f = (x,k,m=5)->l=(.length);x.=map(->it/"#k"=>..0-=/ +$/;m>?=5+l ..0);i=0;[..0&&..0+' '*(m- l ..0)+k+..1 for x]=>while i<(l ..),++i=>j=(s=..[i])lastIndexOf ' ' 93;(..splice i+1 0 ' '*m+k+s[j to]*'';s.=substr 0 j) if 94<l s;..[i]=s
    
console.log (f s / '\n', '#') * \\n

output:

this is kod     # Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod
                # tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim
                # veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea
                # commodo consequat. Duis aute irure dolor in reprehenderit in voluptate
                # velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat
                # cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id
                # est laborum.
d               # y

efgh            # z

Java, 347 + 19 = 366 bytes

Requires

import java.util.*;

Thus the +19 bytes.

(c,s)->{int p=0,i=0,t;String l;for(;i<c.size();i++){l=c.get(i);l=l.replaceAll(" *"+s,s);p=Math.max(l.indexOf(s),p);c.set(i,l);}p+=5;for(i=0;i<c.size();i++){l=c.get(i);t=l.indexOf(s);while(t>-1&t<p)l=l.substring(0,t)+" "+l.substring(t++);t=93;if(l.length()>t){while(l.charAt(t)!=' ')t--;c.add(i+1,s+l.substring(t));l=l.substring(0,t);}c.set(i,l);}}

Takes in the format f.accept(List<String> code, String seperator). Formats in-place. A version that creates and returns a new List<String> would be trivial to implement but cost some bytes.

Indented + example usage:

static BiConsumer<List<String>, String> prettify = (code, seperator) -> {
    int space = 0, i=0, t;
    String line;
    for (; i<code.size(); i++) { // for each line
        line = code.get(i); // get line
        line = line.replaceAll(" *" + seperator, seperator); // strip space before seperator
        space = Math.max(line.indexOf(seperator), space); // save biggest space until seperator
        code.set(i, line); // save line
    }
    space += 5;
    for (i=0; i<code.size(); i++) { // for each line
        line = code.get(i); // get line
        t = line.indexOf(seperator); // get index of seperator
        while (t>-1&t<space) // while the seperator exists and is further left than desired
            line = line.substring(0,t) + " " + line.substring(t++); // move it right by adding a space before it
        t = 93; // get desired line length
        if (line.length()>t) { // if the line is longer than that
            while (line.charAt(t)!=' ') t--; // scan backwards for a space
            code.add(i+1, seperator + line.substring(t)); // add a line after this one with seperator and the rest of the line
                                                          // the next pass will space it correctly
            line = line.substring(0,t); // cut off this line at that point
        }
        code.set(i, line); // save edited line back to List
    }
};

public static void main(String[] args) {
    List<String> code = new ArrayList<>();
    code.add("shM-crz1dc4.\"ANDBYOROF  # z = input");
    code.add("");
    code.add("     rz1      # convert input to uppercase");
    code.add("    c   d        # split input on spaces");
    code.add("         c4.\"ANDBYOROF        # create a list of the words from a packed string which shall be ignored");
    code.add("   -          # filter those words out");
    code.add(" hM                # only take the first letter of all words");
    code.add("s                   # join them into one string");
    prettify.accept(code, "#");
    code.stream().forEach(System.out::println);
}

... I should probably run this through itself :P


Ruby, 245 237 220 216 212 209 205 bytes

Anonymous function. Pretty basic approach (find max length, add 5, then do processing on each line, with recursion to deal with wrapping) and there might be another approach that saves more bytes.

I deleted the answer earlier that didn't fulfill all the requirements; I didn't want to have a half-answered code as an answer (it was getting downvotes for being incomplete too) but it should do everything the question asks for, now.

->x,d{l,S=0," "
s=->n{m,q=n.size,94-l-d.size
m>q ?(i=n.rindex(S,q)
n[0,i]+"
"+S*l+d+s[n[i+1,m]]):n}
x.map{|n|c,t=n.split d
c=(c||S).rstrip
l=[l,5+c.size].max
[c,t]}.map{|c,t|c+S*(l-c.size)+d+s[t]if t}*"
"}

Changelog:

  • Saved some bytes by leveraging some of the promises in the input, especially the promise that all non-empty lines have the separator character and an explanation.
  • Managed to golf a little more by saving the split strings from the first map call and taking out some unnecessary strip functions based on the promise that the words in the explanation always have exactly one space between them. Also, " " is assigned to a constant now since I use it so much.
  • Chained both of the map calls together by leveraging the power of higher-order functions, meaning that the first map call will set the length variable l correctly even if it's called after the declaration of the helper function s. -4 bytes.
  • Abused multiline strings to replace \n with actual newlines, plus a little trick using if over ternary operators (when join is called on an array with nil values, they become empty strings)
  • .join can apparently be replaced with a *.