[Question]
  [
Consider the following alphabetically sorted list of words:
```
balderdash
ballet
balloonfish
balloonist
ballot
brooding
broom
```
All of the words start with `b`, and the first 5 start with `bal`. If we just look at the first 2 words:
```
balderdash
ballet
```
we could write instead:
```
balderdash
  +let
```
where the `' '` is used where a word shares a prefix character with the previous word; except for the `'+'` character which indicates the LAST character where the second word shares a prefix with the previous word.
This is a sort of ['trie'](https://en.wikipedia.org/wiki/Trie) visualization: the parent is '`bal`', and has 2 descendants: `'derdash'` and `'let'`.
With a longer list, such as:
```
balderdash
ballet
brooding
```
we can additionally use the pipe character `'|'` to make it clearer where the shared prefix ends, as follows:
```
balderdash
| +let
+rooding
```
and the equivalent tree would have a root of `'b'` having two children: the subtree having root `'al'` and and its two children `'derdash'` and `'let'`; and `'rooding'`.
If we apply this strategy to our original list,
```
balderdash
ballet
balloonfish
balloonist
ballot
brooding
broom
```
we get output that looks like:
```
balderdash    
| +let     
|  +oonfish
|   | +ist 
|   +t     
+rooding   
   +m 
```
If two consecutive words in the list have no shared prefix, no special characters are substituted; e.g. for the list:
```
broom
brood
crude
crumb
```
we want the output:
```
broom
   +d
crude
  +mb
```
## Input
The words in the input will be made up of only alphanumerics (no spaces or punctuation); this may be in the form of a list of strings, a single string, or any other reasonable approach, as long as you specify your chosen format. No two consecutive words will be the same. The list will be alphabetically sorted.
## Output
Your output can contain trailing whitespace per line or in total, but no leading whitespace. A list of strings or similar would also be acceptable.
This is [code-golf](/questions/tagged/code-golf "show questions tagged 'code-golf'"); the shortest code in each language retains bragging rights. The usual prohibitions against loopholes apply.
## Test Cases
```
Input:
apogee
apology
app
apple
applique
apply
apt
Output:
apogee     
 |+logy    
 +p        
 |+le      
 | +ique   
 | +y      
 +t        
Input:
balderdash
ballet
balloonfish
balloonist
ballot
brooding
broom
donald
donatella
donna
dont
dumb
Output:
balderdash 
| +let     
|  +oonfish
|   | +ist 
|   +t     
+rooding   
   +m      
donald     
| |+tella  
| +na      
| +t       
+umb 
```
  
[Answer]
# [Retina 0.8.2](https://github.com/m-ender/retina/wiki/The-Language/a950ad7d925ec9316e3e2fb2cf5d49fd15d23e3d), ~~58~~ 57 bytes
```
^((.*).)(?<=\b\1.*¶\1)
$.2$* +
m)+`^(.*) (.*¶\1[+|])
$1|$2
```
[Try it online!](https://tio.run/##LYw7DsMgEER7TuGCgo@EhOtEOUgcZKwlCRIfCZPO58oBcjG8Jm72Pc2Mtrjqk23NMKYEV5zdLlczaSV@30lzQtVIxSBJ5HI2x2Jg/@outwfWeqNja4sN4ArY9U1Qg6sdOaenPyN0v54xouQMPr26RAI54YOO6kKwh6V@K4FPXHY "Retina 0.8.2 – Try It Online") Link includes one test case. Edit: Saved 1 byte thanks to @FryAmTheEggman pointing out that I overlooked a switch from `\b` to `^` made possible by the `m)`. Explanation:
```
m)
```
Turn on per-line `^` for the whole program.
```
^((.*).)(?<=^\1.*¶\1)
$.2$* +
```
For each word, try to match as much as possible from the beginning of the previous word. Change the match to spaces, except the last character, which becomes a `+`.
```
+`^(.*) (.*¶\1[+|])
$1|$2
```
Repeatedly replace all spaces immediately above `+`s or `|`s with `|`s.
[Answer]
# JavaScript (ES6), 128 bytes
Expects and returns a list of lists of characters.
```
a=>a.map((w,y)=>a[~y]=w.map(m=(c,x)=>(p=a[y-1]||0,m|=c!=p[x])?c:p[x+1]==w[x+1]?' ':(g=y=>a[y][x]<1?g(y+1,a[y][x]='|'):'+')(-y)))
```
[Try it online!](https://tio.run/##jZDBboQgFEX3fgV1A0QldTsp44dYFoygdYJAxalDYvrrlppZKJMmXT3Oyc3lwZV/cdeMvZ0KbYRcW7pyeuZk4BahOfc4QP3tGZ03NVDU5PcgkaW89kXJluU1HxbavFBb3xmumlOYWckonbdZQQBPqKP@t8izkHkrqw75rMwfTOEC8QlmEKPCY4zXxmhnlCTKdKhFdQJATQhJuTWdlCnLdyJE/MHYIykZcf95i9WxYEpZwvD2WAfoGThyNb1GEGL8OL1riEEGtpkkfyx74UrIUXD3sWsPUskpEsbotn@KBdu7p@hBjMaIXneRGnYsjA5rRGKSSvGj0xHvrxG34fKvL8HrDw "JavaScript (Node.js) – Try It Online")
### How?
Spaces and `+`'s can be inserted by walking through the first to the last word in order, but `|`'s can only be inserted *a posteriori* once a `+` has been identified. This could be achieved by doing two distinct passes, but instead we save a pointer to each modified entry in `a[~y]` so that it can later be updated again within the same `map()` loop.
In theory, a simpler workaround would be to walk through the words in reverse order and to reverse the output as well at the end of the process. But this is a bit costly in JS and I didn't find a way to get a shorter version with this method.
```
a =>                           // a[] = input array
  a.map((w, y) =>              // for each word w at position y in a[]:
    a[~y] =                    //   save a pointer to the current entry in a[~y]
    w.map(m =                  //   initialize m to a non-numeric value
      (c, x) => (              //   for each character c at position x in w:
        p = a[y - 1] || 0,     //     p = previous word or a dummy object
        m |= c != p[x]         //     set m = 1 as soon as w differs from p at this position
      ) ?                      //     if w is no longer equal to p:
        c                      //       append c
      :                        //     else:
        p[x + 1] == w[x + 1] ? //       if the next characters are still matching:
          ' '                  //         append a space
        : (                    //       else:
            g = y =>           //         g() = recursive function to insert pipes
            a[y][x] < 1 ?      //           if a[y][x] is a space:
              g(               //             do a recursive call to g()
                y + 1,         //               with y + 1
                a[y][x] = '|'  //               and overwrite a[y][x] with a pipe
              )                //             end of recursive call
            :                  //           else:
              '+'              //             make the whole recursion chain return a '+'
                               //             which will be appended in the current entry
          )(-y)                //         initial call to g() with -y (this is ~y + 1)
    )                          //   end of map() over the characters
  )                            // end of map() over the words
```
[Answer]
# [JavaScript (Node.js)](https://nodejs.org), 125 122 118 117 bytes
```
a=>a.map((w,i)=>a[i]=w.map((T,k)=>+i&&l[k]==T?l[-~k]<w[-~k]?(g=_=>a[--i][k]<"+"?g(a[i][k]="|"):"+")():" ":(i=l=w,T)))
```
[Try it online!](https://tio.run/##jZDRboMgGIXvfQrCRYWoPEBT6kt4x8hCCzoqghU7s2TZqzt0u1CaJbs6nC@H8/9wE@/CXwfdj4V1Us01nQU9C9KJHqEp1zgYpjmdfkiVt4Fk@nAwrOWUVqVhxVfLT9MqJWro63KjKDQPgRPMYNmgpWGJw0@IjwFhFATAI9LU0CmvMMbz1VnvjCLGNahGLAGAEUKg6F2jFOT5BoTIx470e2dU5PX9EaN9wQh5wvH6RA/oGXhyc9qiNMX49/RiUwwysGqS/LHsRRipBin826Y9QKPGCDhna/0UC1T7p@gODM5JbZsIdRsvnQ1rRGBUxog9s5HfjpGP7vKvL8HzNw "JavaScript (Node.js) – Try It Online")
* thanks to @Arnauld for tio testing :)
[Answer]
# Python, ~~263~~ 260 bytes
-*3 bytes thanks to Jonathan Frech*
Code:
```
p=lambda t,f,g:"\n".join([(f[:-1]+"+"if(a!=min(t))*g else"")+a+p(t[a],(f+" "if len(t[a])>1or a==max(t)else f[:-1]+"| "),1)for a in t])if t else""
def a(t,x):
 if x:c=x[0];t[c]=c in t and t[c]or{};a(t[c],x[1:])
def f(*s):t={};[a(t,i)for i in s];return p(t,"",0)
```
[Try it Online!](https://tio.run/##pVDBbsMgDL3zFYwTNKxqtFsq9iNZDrRAykQgS1wp1bZvzwzNdtpl2gG/h@33bBhvcEnxaV1HFfRwMpqCdLJv2Etk@9fkI2@5a5vHuqtYxbzj@kENmAUhdj21YbaMiUpXI4dWd5K7ilFso8HGkhHPdZqoVmrQC4qygH77fVAmZC1cbqA@UugEKmFzJcY6qjnIRTSEYmFpzmppD90R2nOnzkVBdTQ039P0/nnEbqRyaeumE0Xv@G4WDSgsttnLl2k@a@fuOFm4TpHi7pIxeRDrOPkIlKOKMXbSwdjJ6PlCkAYLBVKKzm8p5H7e0ghTSsbHvpABDfbzGDzw/JVCCEI2d/ywH36fRPSYemszhNTfEMd8gi3Rv13vJBeA/Mn4f28gJkU0KAA2BJ1ZLBGIuQ6nX5ZZvwA)
Explanation:
This solution builds a trie out of the input words and recursively parses it into the required output. The a function takes a trie t and a string s and adds x to t. Tries are implemented as nested dictionaries. Each dictionary represents a node in the trie. For example, the dictionary representing the trie generated by the first test case looks like this: 
```
{'b': {'a': {'l': {'d': {'e': {'r': {'d': {'a': {'s': {'h': {}}}}}}}, 'l': {'e': {'t': {}}, 'o': {'o': {'n': {'f': {'i': {'s': {'h': {}}}}, 'i': {'s': {'t': {}}}}}, 't': {}}}}}, 'r': {'o': {'o': {'d': {'i': {'n': {'g': {}}}}, 'm': {}}}}}}
```
The p function recurses through this structure and generates the string representation of the trie expected by the challenge. The f function takes a bunch of strings as arguments, adds them all to a trie with a, then returns the result of calling p on the trie.
[Answer]
# [C (gcc)](https://gcc.gnu.org/), 165 155 bytes
Takes three arguments:
* `char** a` : an array of null-terminated words
* `char* m` : an array of the length of each word
* `int n` : the number of words in the array
```
f(a,m,n,i,j)char**a,*m;{for(i=n;--i;)for(j=0;j<m[i]&j<m[i-1]&a[i][j]==a[i-1][j];j++)a[i][j]=a[i][j+1]^a[i-1][j+1]?43:++i<n&j<m[i]&a[i--][j]%81==43?124:32;}
```
[Try it online!](https://tio.run/##fVFdi4MwEHz3VwShJdbI1dqHo6n0h3gepBrbiG5KtBxc8bd7Gz9q@3Ig7MzOZmYTs@CSZX1fUMFqBkyx0suuwmw2gm1q/ii0oSoGHgSKe5aU8ZaXxzpR6XooQZiuBbKkTONYDBwhL33fm9tj9cP0e9YRn/bRwffVEdaTm9UCO7/6DON4H53C3f4Q7XjXD/uQSjVtkpKYPBxC3LOocmly0VxdNvFKtgvWGgr1KmIDDV74jI3WuYLLwuoR5howY8GtrCrxpLDAySi/12fX6bjjKGhJLRRQb9jVUsC9G/UrdUHtPTzy8UqTbepxnBwv@qNN3iSQzh1SSZgofvgPCLWWCi23HMuRABZ87yGNTOeVfaqmNfn9NmaoMYMMdrOK@E3tphA6mDA7ywh4S/b/0TeDckHdVfMFLntuMgUXRkr61uucrv8D "C (gcc) – Try It Online")
[Answer]
# [Perl 6](https://github.com/nxadm/rakudo-pkg), ~~149 144~~ 142 bytes
```
{1 while s/(\n.*)\s(.*)$0(\+|\|)/$0|$1$0$2/;$_}o{$=({.[1].subst(/^(.+)<?{.[0].index($0)eq 0}>/,{' 'x$0.ords-1~'+'})}for '',|$_ Z$_).join("
")}
```
[Try it online!](https://tio.run/##LYzLbsMgFAX3/oqr6KpAnGLcRTd59D9ap5YtcEKEoQVHTWTTX3eplc2Z0SzOl/Lmde7v8NTBHuaxhJ@zNgpCQSvL16wKNC0KWuVTNbECxYQlCnwptlhHN@KejvyjPPJwbcNAi0/Kc7Z7S00cubZS3SgKpr5BxEOxGQmQGwruvAzP5S/JSWSxcx4I2UxYwzvWjF@ctnSVrVicQ3OHju7axkjlZRPOWVKjhgXO2U4/UnIdHjnBOye1PS3SZ9LZdLBgUMY0/2aXHTJ57dsD285/ "Perl 6 – Try It Online")
I'm sure this can be golfed a more, especially as I'm not an expert on regexes. This uses much the same process as [Neil's Retina answer](https://codegolf.stackexchange.com/a/170584/76162).
[Answer]
# [Ruby](https://www.ruby-lang.org/), 118 bytes
```
->a{i=1;a.map{s="";a[i+=j=-1].chars{|c|a[i][j+=1]=i<0&&a[i-1][/^#{s+=c}/]?a[i+1][j]=~/[|+]/??|:?\s:c}[/[| ]\b/]&&=?+}}
```
[Try it online!](https://tio.run/##Rc7BcoMgEAbgu0@RsTNeaEK9xm54EEJmFkWDg2JFDxk1r26h0ebE9@8PO/SjfKwlrMcLThrSDE8NdpODOM6QawI1HFNxyu/Yu2nOZz8TvCaQCtDfX0nis@85vX1MjkC@UMHCMz@qBTwpn4mgjM1ndnXnfOF@cBBXSUWSACPLsiLwGDtbKRV/RkHGVo8Xu@0waof@Gf@9XRpiEUXSL5FoCtUX6O6h8MmoYZe1banfhY/avcuXemsL3Va7m4DCtn7rrkEZg1tod/w9LsZGhn@UHEXWjYM7oLfcLNdf "Ruby – Try It Online")
Accepts an array of strings, outputs by modifying the original input array in-place.
## Explanation
The basic string transformation is not too complex, but in order to insert vertical pipes properly, we need to iterate in reverse order, and since `reverse` method is quite verbose, we'll do it in a trickier way. Here, we use `map` just to run the loop, leave the first word alone, and then iterate from the end using negative indices:
```
->a{
 i=1;                   #Initialize word indexer
 a.map{                 #Loop
  s="";                 #Initialize lookup string
  a[i+=j=-1]            #Initialize char indexer and decrement i
  .chars{|c|            #Loop through each char c of current word
   a[i][j+=1]=          #Mofify current word at position j 
    i<0&&               #If it's not the first word and
    a[i-1][/^#{s+=c}/]? #Word above matches current one from start to j
     a[i+1][j]=~/[|+]/? #Then if char below is | or +
      ?|:?\s:c          #Then set current char to | Else to Space Else leave as is
  }[/[| ]\b/]&&=?+      #Finally, replace Space or | at word boundary with +
 }
}
```
[Answer]
# [Python 2](https://docs.python.org/2/), 191 bytes
```
def f(w,r=['']):
 for b,c in zip(w[1:],w)[::-1]:
	s='';d=0
	for x,y,z in zip(r[0]+b,b,c+b):t=s[-1:];s=s[:-1]+[['+'*(s>'')+y,t+' |'[x in'+|']][y==z],t+y][d];d=d|(y!=z)
	r=[s]+r
 return[w[0]]+r
```
[Try it online!](https://tio.run/##RZHBcoMgEIbP8SnoabWQTtIjGfoilIMWNHQIWMAxOL67xUab037/7v/vMkOf4tXZ92WRqkVtORLPOICoaIFa51FDvpC2aNJ9OfIzFWSsOKXHs6DFITCAi2Sn4rA67ySRafd6fhK4ITmNm4pGFvgxhy8hwxrGnAOG1zJ8AFQ4kYgBzcDvOQ54BiF4YmwSuZ8ElyIfkXOZXthUFYf8viCwL5BXcfCWj/lU1kvvtY0IPi28fTtty7bkUPeuUwoIWsm4Lj2w34pRO@if4Z83U1xLUxupvKzDdVNG7X3jnG31c5ClDs/hg7xzUttu59sK0tm8daeojKk3YXf4C8vh1uSPqIrlFw "Python 2 – Try It Online")
]