One of the issues I have with ams alignment environments is that they use "cells" which change in size to fit their content. This is required for all cells which are used for alignment, but I feel it is not really required for the last cell in each row (even if that row contains fewer cells). I also don't like the lr alignment and the extra spacing that align adds. All of this causes unintuitive spacing (for me), which I always struggle with. I decided to write a custom environment that behaves like I would expect.
The custom environment should treat the input as a block. Within this block, & symbols are treated as alignment points with no additional spacing added. When these & symbols are encountered, the effect (and the only effect) is that any text appearing after them will be aligned. For example here:
AAAAAAAAAAA \\
BB & C \\
EEEEEE & FFFFF \\
The first line does not affect alignment at all. The second line "defines" an alignment point which is not used up to here (in particular, the first line does not change the alignment here). The third line causes the left column to increase in size so that C and F are aligned.
I don't claim that this is impossible to achieve with ams alignment. However, adding the necessary &, math*lap and nested aligned commands is always a mystery to me, so I wanted something simple.
I figured out how to use a combination of array and multicolumn to achieve what I want. Essentially, I used the extended array package to default to >{{}}l<{{}} for each column (the {} are to fix spacing of binary operators) and to have the last column in every row span all remaining columns. I am not familiar enough with array or TeX to do this properly, so I instead used my limited knowledge of expl3 to add the necessary syntax to a more intuitive text. The result is in the following MWE, which I would like to solicit comment/feedback on.
In particular, is there already a way to achieve what I want without a custom environment? Or a better way than using array in my custom environment? Also, is my expl3 code correct or can it be improved? (I didn't figure out how to make it so that it works if I replace all the equations with a command that expands into the equations)
\documentclass{article}
\usepackage{array}
\usepackage{mathtools}
\ExplSyntaxOn
% ==== Variables for alignblock ====
\int_new:N \l_alignblock_col_max_int
\int_new:N \l_alignblock_row_cols_int
\int_new:N \l_alignblock_col_gap_int
\seq_new:N \l_alignblock_rows_seq
\seq_new:N \l_alignblock_cells_seq
\tl_new:N \l_alignblock_build_tl
\tl_new:N \l_alignblock_colspec_tl
% ==== alignblock environment ====
\NewDocumentEnvironment{alignblock}{O{}+b}
{
% Split rows
\seq_set_split:Nnn \l_alignblock_rows_seq { \\ } {#2}
% Compute max column count
\int_zero:N \l_alignblock_col_max_int
\seq_map_inline:Nn \l_alignblock_rows_seq
{
\seq_set_split:Nnn \l_alignblock_cells_seq { & } { ##1 }
\int_set:Nn \l_alignblock_col_max_int
{ \int_max:nn { \l_alignblock_col_max_int } % { \l_alignblock_row_cols_int }
{ \seq_count:N \l_alignblock_cells_seq }}}
% Array body
\tl_build_begin:N \l_alignblock_build_tl
\tl_build_put_right:Nn \l_alignblock_build_tl {
\begingroup\everymath{\displaystyle}\setlength{\arraycolsep}{0pt}}
\tl_set:Nx \l_alignblock_colspec_tl
{ \tl_if_blank:nTF {#1}
{ r*{\int_use:N \l_alignblock_col_max_int}{>{{}}l<{{}}} }
{ #1*{\int_use:N \l_alignblock_col_max_int}{>{{}}l<{{}}} }
}
\tl_build_put_right:Nx \l_alignblock_build_tl {
\begin{array}[t]{\l_alignblock_colspec_tl}}
\seq_map_indexed_inline:Nn \l_alignblock_rows_seq % Loop over lines
{
\seq_set_split:Nnn \l_alignblock_cells_seq { & } { ##2 }
\int_set:Nn \l_alignblock_row_cols_int { \seq_count:N \l_alignblock_cells_seq }
\int_set:Nn \l_alignblock_col_gap_int
{ \l_alignblock_col_max_int - \l_alignblock_row_cols_int + 1 }
\seq_map_indexed_inline:Nn \l_alignblock_cells_seq % Loop over cells
{
\int_compare:nNnTF { ####1 } < { \l_alignblock_row_cols_int }
{ \tl_build_put_right:Nn \l_alignblock_build_tl { ####2 & } }
{
\int_compare:nNnTF { \l_alignblock_col_gap_int } = { 1 }
{ \tl_build_put_right:Nn \l_alignblock_build_tl { ####2 } }
{
\tl_build_put_right:Nx \l_alignblock_build_tl
{ \exp_not:N\multicolumn{ \int_use:N \l_alignblock_col_gap_int }{>{{}}l<{{}}} }
\tl_build_put_right:Nn \l_alignblock_build_tl { { ####2 } }}}}
\int_compare:nNnT { ##1 } < { \seq_count:N \l_alignblock_rows_seq }
{ \tl_build_put_right:Nn \l_alignblock_build_tl { \\[\jot] } }}
\tl_build_put_right:Nn \l_alignblock_build_tl { \end{array}\endgroup }
\tl_build_end:N \l_alignblock_build_tl
% \par\noindent\ttfamily % DEBUG
% \detokenize\expandafter{\l_alignblock_build_tl}
% \par\normalfont
\tl_use:N \l_alignblock_build_tl}{}
% ==== Variables for multlineR ====
\seq_new:N \l_multlineR_lines_seq
\tl_new:N \l_multlineR_first_tl
\tl_new:N \l_multlineR_last_tl
\tl_new:N \l_multlineR_body_tl
% ==== multlineR environment ====
\NewDocumentEnvironment{multlineR}{s O{} +b}
{
\seq_set_split:Nnn \l_multlineR_lines_seq { \\ } { #3 }
\seq_pop_left:NN \l_multlineR_lines_seq \l_multlineR_first_tl
\seq_pop_right:NN \l_multlineR_lines_seq \l_multlineR_last_tl
\tl_clear:N \l_multlineR_body_tl
% first line
\tl_put_right:NV \l_multlineR_body_tl \l_multlineR_first_tl
\tl_put_right:Nn \l_multlineR_body_tl { \\ \begin{alignblock}[#2] }
% middle lines
\seq_map_inline:Nn \l_multlineR_lines_seq
{ \tl_put_right:Nn \l_multlineR_body_tl { &{} ##1 \\ } }
% last line
\tl_put_right:Nn \l_multlineR_body_tl { &{} }
\tl_put_right:NV \l_multlineR_body_tl \l_multlineR_last_tl
\tl_put_right:Nn \l_multlineR_body_tl { \end{alignblock} }
% wrap in multline or multline*
\IfBooleanTF{#1}
{ \begin{multline*}\l_multlineR_body_tl\end{multline*} }
{ \begin{multline}\l_multlineR_body_tl\end{multline} }
}{}
\NewDocumentEnvironment{multlineR*}{+b}
{ \multlineR*{#1} }{}
\ExplSyntaxOff
\begin{document}
\textbf{alignblock} vs \textbf{align} example usage (same input):
\[
\begin{alignblock}
\textnormal{\textbf{alignblock}}\\
AB &= a+b+c+d+e \\
&= a & + b+WW &+d \\
& & + o+q &+r \\
&= aB & +o+p+q+r \\
&= a+b+c+d+e \\
&= a & +b &+e \\
& &+ c+d+e
\end{alignblock}\hskip1cm
% A (useless) comparision
\begin{aligned}[t]
\textnormal{\textbf{aligned}}\\
AB &= a+b+c+d+e \\
&= a & + b+WW &+d \\
& & + o+q &+r \\
&= aB & +o+p+q+r \\
&= a+b+c+d+e \\
&= a & +b &+e \\
& &+ c+d+e
\end{aligned}
\]
\textbf{multlineR} example usage:
\begin{multlineR*}
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\\
&= a & + b+WW &+d \\
& & + o+q &+r \\
&= aB & +o+p+q+r \\
&= a+b+c+d+e \\
&= a & +b &+e \\
& &+ c+d+e
\end{multlineR*}
\end{document}

alignis because it is not designed for multiple alignment points in an expression but for multiple equations per linea=b c=dyou need space between the equations. usealignatfor alignment points with no added space.=??? (I would show a version withalignatbut not really sure if you really intend the first equation to start with&and have nothing=something[code-review]is on-topic (and kind of a special case), so I've added that since it seems to fit the question. Feel free to revert if that part wasn't your “main” question.