Skip to content

Commit

Permalink
Implement grid alignment.
Browse files Browse the repository at this point in the history
  • Loading branch information
Gbr authored and Gbr committed Jun 9, 2018
1 parent b1b3e4e commit 1962e8b
Show file tree
Hide file tree
Showing 11 changed files with 327 additions and 61 deletions.
62 changes: 47 additions & 15 deletions net.certiv.adept/src/net/certiv/adept/format/AlignProcessor.java
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
import net.certiv.adept.unit.AdeptComp;
import net.certiv.adept.unit.TableMultilist;
import net.certiv.adept.unit.TreeMultilist;
import net.certiv.adept.util.Maths;
import net.certiv.adept.util.Strings;

/**
Expand All @@ -32,6 +33,7 @@ public AlignProcessor(FormatterOps ops) {

public void alignFields() {
ops.buildLinesIndexes();
ops.collectLinears();

for (Group group : ops.data.groupIndex) {

Expand All @@ -52,6 +54,10 @@ public void alignFields() {
handleListAlign(lines, false);
break;

case LINEAR:
handleLikeAlign(lines, true);
break;

default:
break;
}
Expand Down Expand Up @@ -117,38 +123,53 @@ private void handleListAlign(TreeMultilist<Integer, AdeptToken> alignables, bool
}
}

// Update line numers to account for edits
private TreeMultilist<Integer, AdeptToken> update(TreeMultilist<Integer, AdeptToken> lines) {
TreeMultilist<Integer, AdeptToken> updated = new TreeMultilist<>();
updated.setValueComparator(AdeptComp.Instance);
for (AdeptToken token : lines.valuesAll()) {
Integer modLine = ops.tokenLineIndex.get(token.getTokenIndex());
updated.put(modLine, token);
private void handleLikeAlign(TreeMultilist<Integer, AdeptToken> lines, boolean tabAlignFirst) {
Grid grid = new Grid(ops, lines);

for (int cIdx = 0; cIdx < grid.size(); cIdx++) {
int alignCol = 0;
if (cIdx == 0 && tabAlignFirst) {
alignCol = grid.minTabCol(cIdx);
} else {
alignCol = grid.minCol(cIdx);
}

for (int lnum : lines.keySet()) {
if (!grid.isEmpty(cIdx, lnum)) {
AdeptToken token = grid.get(cIdx, lnum);
if (alignCol != token.visCol()) {
boolean mid = cIdx != 0 && cIdx != grid.size() - 1;
int delt = Maths.delta(alignCol, token.visCol());
if (!mid || (mid && delt < 7)) {
ops.prepEditAndShiftLine(lnum, token, alignCol);
}
}
}
}
}
return updated;
}

private int minTabCol(TreeMultilist<Integer, AdeptToken> group, int col) {
int minCol = minCol(group, col);
return Strings.nextTabCol(minCol, ops.settings.tabWidth);
private int minTabCol(TreeMultilist<Integer, AdeptToken> alignables, int col) {
int min = minCol(alignables, col);
return Strings.nextTabCol(min, ops.settings.tabWidth);
}

private int minCol(TreeMultilist<Integer, AdeptToken> alignables, int col) {
int minCol = 0;
int min = 0;
for (int line : alignables.keySet()) {
List<AdeptToken> alignTokens = alignables.get(line);
if (alignTokens.size() > col) {
AdeptToken alignable = alignTokens.get(col);
AdeptToken prior = ops.priorInLine(line, alignable);

if (prior != null) {
minCol = Math.max(minCol, prior.visCol() + prior.getText().length() + 1);
min = Math.max(min, prior.visCol() + prior.getText().length() + 1);
} else {
minCol = Math.max(minCol, alignable.dent().indents * ops.settings.tabWidth);
min = Math.max(min, alignable.dent().indents * ops.settings.tabWidth);
}
}
}
return minCol;
return min;
}

private int countMaxCols(TreeMultilist<Integer, AdeptToken> alignables) {
Expand All @@ -158,4 +179,15 @@ private int countMaxCols(TreeMultilist<Integer, AdeptToken> alignables) {
}
return max;
}

// Update line numers to account for edits
private TreeMultilist<Integer, AdeptToken> update(TreeMultilist<Integer, AdeptToken> lines) {
TreeMultilist<Integer, AdeptToken> updated = new TreeMultilist<>();
updated.setValueComparator(AdeptComp.Instance);
for (AdeptToken token : lines.valuesAll()) {
Integer modLine = ops.tokenLineIndex.get(token.getTokenIndex());
updated.put(modLine, token);
}
return updated;
}
}
87 changes: 73 additions & 14 deletions net.certiv.adept/src/net/certiv/adept/format/FormatterOps.java
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@

import net.certiv.adept.Settings;
import net.certiv.adept.Tool;
import net.certiv.adept.format.plan.Group;
import net.certiv.adept.format.plan.Scheme;
import net.certiv.adept.lang.AdeptToken;
import net.certiv.adept.lang.ParseRecord;
import net.certiv.adept.model.DocModel;
Expand All @@ -25,6 +27,8 @@
/** Operations to collect and manage {@code TextEdit}s during the multiple stages of formatting. */
public class FormatterOps {

private static final String ErrVisCol = "Err: viscol %s should have been %s for %s";

Tool tool;
Document doc;
ParseRecord data;
Expand Down Expand Up @@ -88,10 +92,37 @@ protected int getAlign(int index) {

// -----------------------------------------------------------------------------

/** Find and add a meta group for each set of linear groups. */
protected void collectLinears() {
Group linears = new Group();
for (Group group : data.groupIndex) {
for (Scheme scheme : group.getSchemes()) {
if (group.linear(scheme)) {
TreeMultilist<Integer, AdeptToken> members = group.get(scheme);
Integer key = members.firstKey();
linears.addMembers(Scheme.LINEAR, key, members.get(key));
}
}
}

Group group = new Group();
TreeMultilist<Integer, AdeptToken> members = linears.get(Scheme.LINEAR);
for (int lnum : members.keySet()) {
if (group.isEmpty() || group.contiguous(Scheme.LINEAR, lnum)) {
group.addMembers(Scheme.LINEAR, lnum, members.get(lnum));
} else {
data.groupIndex.add(group);
group = new Group();
group.addMembers(Scheme.LINEAR, lnum, members.get(lnum));
}
}
if (!group.isEmpty()) data.groupIndex.add(group);
}

/**
* Rebuilds the line indexes to reflect edits between real tokens. Appends each real token to the
* modLineTokenIndex. Creates new lines as appropriate. Updates the {@code visCol} field of the
* given token to refect any formatting edits.
* lineTokenIndex. Creates new lines as appropriate. Updates the {@code visCol} field of the given
* token to refect any formatting edits.
*/
protected void buildLinesIndexes() {
lineTokensIndex.clear();
Expand Down Expand Up @@ -152,23 +183,51 @@ protected TextEdit updateOrCreateCommentEdit(AdeptToken token, String replacemen
* @param token
* @param toVisCol
*/
protected void prepEditAndShiftLine(int lineNum, AdeptToken token, int toVisCol) {
if (token.visCol() == toVisCol) return;
protected void prepEditAndShiftLine(int lnum, AdeptToken token, int toVisCol) {
int from = calcVisCol(token);
if (token.visCol() != from) {
tool.toolInfo(this, String.format(ErrVisCol, token.visCol(), from, token.toString()));
token.setVisCol(from);
}

List<AdeptToken> fullLine = lineTokensIndex.get(lineNum);
if (from == toVisCol) return;

List<AdeptToken> fullLine = lineTokensIndex.get(lnum);
int idx = fullLine.indexOf(token);
updateOrCreateEditLeft(token, idx, toVisCol);
updateLineVisCols(token);
}

ListIterator<AdeptToken> remainder = fullLine.listIterator(idx + 1);
AdeptToken prior = token;
while (remainder.hasNext()) {
AdeptToken next = remainder.next();
int from = prior.visCol() + prior.getText().length();
String ws = findWsLeft(token);
int width = Strings.measureVisualWidth(ws, settings.tabWidth, from);
token.setVisCol(from + width);
prior = next;
// -----------------------------------------------------------------------------

protected void updateLineVisCols(AdeptToken token) {
int col = calcVisCol(token) + token.getText().length();

int lnum = tokenLineIndex.get(token.getTokenIndex());
List<AdeptToken> fullLine = lineTokensIndex.get(lnum);
int idx = fullLine.indexOf(token);
ListIterator<AdeptToken> reals = fullLine.listIterator(idx + 1);
while (reals.hasNext()) {
AdeptToken real = reals.next();
String lead = findWsLeft(real);
col += Strings.measureVisualWidth(lead, settings.tabWidth, col);
real.setVisCol(col);
col += real.getText().length();
}
}

protected int calcVisCol(AdeptToken token) {
int lnum = tokenLineIndex.get(token.getTokenIndex());
List<AdeptToken> reals = lineTokensIndex.get(lnum);
int idx = reals.indexOf(token);

StringBuilder sb = new StringBuilder();
for (AdeptToken real : reals.subList(0, idx)) {
sb.append(findWsLeft(real));
sb.append(real.getText());
}
sb.append(findWsLeft(token));
return Strings.measureVisualWidth(sb, settings.tabWidth);
}

// -----------------------------------------------------------------------------
Expand Down
116 changes: 116 additions & 0 deletions net.certiv.adept/src/net/certiv/adept/format/Grid.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
package net.certiv.adept.format;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import net.certiv.adept.lang.AdeptToken;
import net.certiv.adept.unit.TreeMultilist;
import net.certiv.adept.util.Strings;

public class Grid {

private FormatterOps ops;
private int first;
private int lcnt;
private List<Col> grid = new ArrayList<>();

class Col {

// the identifying 'mark' for this column
final String mark;

// key=row; value=token
final Map<Integer, AdeptToken> cells = new HashMap<>();

Col(String mark) {
this.mark = mark;
}

void add(int lnum, AdeptToken token) {
cells.put(lnum, token);
}
}

public Grid(FormatterOps ops, TreeMultilist<Integer, AdeptToken> lines) {
this.ops = ops;
this.first = lines.firstKey();
this.lcnt = lines.size();
build(lines);
}

private void build(TreeMultilist<Integer, AdeptToken> lines) {
for (Integer lnum : lines.keySet()) {
List<AdeptToken> tokens = lines.get(lnum);
addRow(lnum, tokens);
}
}

private void addRow(int lnum, List<AdeptToken> tokens) {
int at = 0;
for (int idx = 0; idx < tokens.size(); idx++) {
String mark = tokens.get(idx).getText();
at = findCol(at, mark);
Col col = grid.get(at);
col.add(lnum, tokens.get(idx));
at++;
}
}

private int findCol(int at, String mark) {
for (int cnum = at; cnum < grid.size(); cnum++) {
if (grid.get(cnum).mark.equals(mark)) return cnum;
}
grid.add(new Col(mark));
return grid.size() - 1;
}

public AdeptToken get(int cIdx, int lnum) {
Col col = grid.get(cIdx);
return col.cells.get(lnum);
}

public int minTabCol(int cIdx) {
return Strings.nextTabCol(minCol(cIdx), ops.settings.tabWidth);
}

public int minCol(int cIdx) {
int min = 0;
Col col = grid.get(cIdx);

for (int lnum : col.cells.keySet()) {
AdeptToken token = col.cells.get(lnum);
AdeptToken prior = ops.priorInLine(lnum, token);

if (prior != null) {
min = Math.max(min, prior.visCol() + prior.getText().length() + 1);
} else {
min = Math.max(min, token.dent().indents * ops.settings.tabWidth);
}
}
return min;
}

public boolean isEmpty(int cIdx, int lnum) {
return get(cIdx, lnum) == null;
}

public int size() {
return grid.size();
}

@Override
public String toString() {
StringBuilder sb = new StringBuilder();
for (int lnum = first; lnum < lcnt; lnum++) {
for (Col col : grid) {
AdeptToken token = col.cells.get(lnum);
String txt = (token != null) ? token.getText() : "";
sb.append(String.format(" %2s |", txt));
}
sb.append(Strings.EOL);
}
return sb.toString();
}
}
Loading

0 comments on commit 1962e8b

Please sign in to comment.