merge all into single repo
This commit is contained in:
@@ -0,0 +1,37 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<parent>
|
||||
<artifactId>gumtree</artifactId>
|
||||
<groupId>com.github.gumtreediff</groupId>
|
||||
<version>2.0.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<artifactId>client.diff</artifactId>
|
||||
<packaging>jar</packaging>
|
||||
<name>GumTree Diff Client</name>
|
||||
<dependencies>
|
||||
<!-- https://mvnrepository.com/artifact/com.sparkjava/spark-core -->
|
||||
<dependency>
|
||||
<groupId>com.sparkjava</groupId>
|
||||
<artifactId>spark-core</artifactId>
|
||||
<version>2.6.0</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.github.gumtreediff</groupId>
|
||||
<artifactId>client</artifactId>
|
||||
<version>2.0.0-SNAPSHOT</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.nanohttpd</groupId>
|
||||
<artifactId>nanohttpd-webserver</artifactId>
|
||||
<version>2.1.1</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.rendersnake</groupId>
|
||||
<artifactId>rendersnake</artifactId>
|
||||
<version>1.8</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
</project>
|
||||
+136
@@ -0,0 +1,136 @@
|
||||
/*
|
||||
* This file is part of GumTree.
|
||||
*
|
||||
* GumTree is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* GumTree is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with GumTree. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Copyright 2011-2015 Jean-Rémy Falleri <jr.falleri@gmail.com>
|
||||
* Copyright 2011-2015 Floréal Morandat <florealm@gmail.com>
|
||||
*/
|
||||
|
||||
package com.github.gumtreediff.client.diff;
|
||||
|
||||
import com.github.gumtreediff.client.Option;
|
||||
import com.github.gumtreediff.client.Client;
|
||||
import com.github.gumtreediff.gen.Generators;
|
||||
import com.github.gumtreediff.matchers.Matcher;
|
||||
import com.github.gumtreediff.matchers.Matchers;
|
||||
import com.github.gumtreediff.tree.TreeContext;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.PrintStream;
|
||||
import java.util.ArrayList;
|
||||
|
||||
public abstract class AbstractDiffClient<O extends AbstractDiffClient.Options> extends Client {
|
||||
|
||||
protected final O opts;
|
||||
public static final String SYNTAX = "Syntax: diff [options] baseFile destFile";
|
||||
private TreeContext src;
|
||||
private TreeContext dst;
|
||||
|
||||
public static class Options implements Option.Context {
|
||||
public String matcher;
|
||||
public ArrayList<String> generators = new ArrayList<>();
|
||||
public String src;
|
||||
public String dst;
|
||||
|
||||
@Override
|
||||
public Option[] values() {
|
||||
return new Option[] {
|
||||
new Option("-m", "The qualified name of the class implementing the matcher.", 1) {
|
||||
@Override
|
||||
protected void process(String name, String[] args) {
|
||||
matcher = args[0];
|
||||
}
|
||||
},
|
||||
new Option("-g", "Preferred generator to use (can be used more than once).", 1) {
|
||||
@Override
|
||||
protected void process(String name, String[] args) {
|
||||
generators.add(args[0]);
|
||||
}
|
||||
},
|
||||
new Option.Help(this) {
|
||||
@Override
|
||||
public void process(String name, String[] args) {
|
||||
System.out.println(SYNTAX);
|
||||
super.process(name, args);
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
void dump(PrintStream out) {
|
||||
out.printf("Current path: %s\n", System.getProperty("user.dir"));
|
||||
out.printf("Diff: %s %s\n", src, dst);
|
||||
}
|
||||
}
|
||||
|
||||
protected abstract O newOptions();
|
||||
|
||||
public AbstractDiffClient(String[] args) {
|
||||
super(args);
|
||||
opts = newOptions();
|
||||
args = Option.processCommandLine(args, opts);
|
||||
|
||||
if (args.length < 2)
|
||||
throw new Option.OptionException("arguments required." + SYNTAX, opts);
|
||||
|
||||
opts.src = args[0];
|
||||
opts.dst = args[1];
|
||||
|
||||
if (Option.Verbose.verbose) {
|
||||
opts.dump(System.out);
|
||||
}
|
||||
}
|
||||
|
||||
///////////////////
|
||||
// TODO after this line it should be rewrote in a better way
|
||||
private Matcher matcher;
|
||||
|
||||
protected Matcher matchTrees() {
|
||||
Matchers matchers = Matchers.getInstance();
|
||||
if (matcher != null)
|
||||
return matcher;
|
||||
matcher = (opts.matcher == null)
|
||||
? matchers.getMatcher(getSrcTreeContext().getRoot(), getDstTreeContext().getRoot())
|
||||
: matchers.getMatcher(opts.matcher, getSrcTreeContext().getRoot(), getDstTreeContext().getRoot());
|
||||
matcher.match();
|
||||
return matcher;
|
||||
}
|
||||
|
||||
protected TreeContext getSrcTreeContext() {
|
||||
if (src == null)
|
||||
src = getTreeContext(opts.src);
|
||||
return src;
|
||||
}
|
||||
|
||||
protected TreeContext getDstTreeContext() {
|
||||
if (dst == null)
|
||||
dst = getTreeContext(opts.dst);
|
||||
return dst;
|
||||
}
|
||||
|
||||
private TreeContext getTreeContext(String file) {
|
||||
try {
|
||||
TreeContext t;
|
||||
if (opts.generators.isEmpty())
|
||||
t = Generators.getInstance().getTree(file);
|
||||
else
|
||||
t = Generators.getInstance().getTree(opts.generators.get(0), file);
|
||||
return t;
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
+77
@@ -0,0 +1,77 @@
|
||||
/*
|
||||
* This file is part of GumTree.
|
||||
*
|
||||
* GumTree is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* GumTree is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with GumTree. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Copyright 2011-2015 Jean-Rémy Falleri <jr.falleri@gmail.com>
|
||||
* Copyright 2011-2015 Floréal Morandat <florealm@gmail.com>
|
||||
*/
|
||||
|
||||
package com.github.gumtreediff.client.diff;
|
||||
|
||||
import com.github.gumtreediff.client.Option;
|
||||
import com.github.gumtreediff.gen.Registry;
|
||||
import com.github.gumtreediff.io.TreeIoUtils;
|
||||
import com.github.gumtreediff.client.Register;
|
||||
import com.github.gumtreediff.matchers.Matcher;
|
||||
|
||||
@Register(name = "axmldiff", description = "Dump annotated xml tree",
|
||||
priority = Registry.Priority.LOW, options = AbstractDiffClient.Options.class)
|
||||
public class AnnotatedXmlDiff extends AbstractDiffClient<AnnotatedXmlDiff.Options> {
|
||||
|
||||
public AnnotatedXmlDiff(String[] args) {
|
||||
super(args);
|
||||
}
|
||||
|
||||
static class Options extends AbstractDiffClient.Options {
|
||||
protected boolean isSrc = true;
|
||||
|
||||
@Override
|
||||
public Option[] values() {
|
||||
return Option.Context.addValue(super.values(),
|
||||
new Option("--src", String.format("Dump source tree (default: %s)", isSrc ? "yes" : "no"), 0) {
|
||||
@Override
|
||||
protected void process(String name, String[] args) {
|
||||
isSrc = true;
|
||||
}
|
||||
},
|
||||
new Option("--dst", String.format("Dump destination tree (default: %s)", !isSrc
|
||||
? "yes" : "no"), 0) {
|
||||
@Override
|
||||
protected void process(String name, String[] args) {
|
||||
isSrc = false;
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Options newOptions() {
|
||||
return new Options();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
Matcher m = matchTrees();
|
||||
try {
|
||||
TreeIoUtils.toAnnotatedXml((opts.isSrc)
|
||||
? getSrcTreeContext()
|
||||
: getDstTreeContext(), opts.isSrc, m.getMappings()
|
||||
).writeTo(System.out);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
/*
|
||||
* This file is part of GumTree.
|
||||
*
|
||||
* GumTree is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* GumTree is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with GumTree. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Copyright 2011-2015 Jean-Rémy Falleri <jr.falleri@gmail.com>
|
||||
* Copyright 2011-2015 Floréal Morandat <florealm@gmail.com>
|
||||
*/
|
||||
|
||||
package com.github.gumtreediff.client.diff;
|
||||
|
||||
import com.github.gumtreediff.actions.ActionGenerator;
|
||||
import com.github.gumtreediff.actions.model.Action;
|
||||
import com.github.gumtreediff.client.Register;
|
||||
import com.github.gumtreediff.io.ActionsIoUtils;
|
||||
import com.github.gumtreediff.matchers.Matcher;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Register(name = "jsondiff", description = "Dump actions in the JSON format",
|
||||
options = AbstractDiffClient.Options.class)
|
||||
public class JsonDiff extends AbstractDiffClient<AbstractDiffClient.Options> {
|
||||
|
||||
public JsonDiff(String[] args) {
|
||||
super(args);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Options newOptions() {
|
||||
return new Options();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
Matcher m = matchTrees();
|
||||
ActionGenerator g = new ActionGenerator(getSrcTreeContext().getRoot(),
|
||||
getDstTreeContext().getRoot(), m.getMappings());
|
||||
g.generate();
|
||||
List<Action> actions = g.getActions();
|
||||
try {
|
||||
ActionsIoUtils.toJson(getSrcTreeContext(), actions, m.getMappings()).writeTo(System.out);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,141 @@
|
||||
/*
|
||||
* This file is part of GumTree.
|
||||
*
|
||||
* GumTree is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* GumTree is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with GumTree. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Copyright 2011-2015 Jean-Rémy Falleri <jr.falleri@gmail.com>
|
||||
* Copyright 2011-2015 Floréal Morandat <florealm@gmail.com>
|
||||
*/
|
||||
|
||||
package com.github.gumtreediff.client.diff;
|
||||
|
||||
import com.github.gumtreediff.actions.ActionGenerator;
|
||||
import com.github.gumtreediff.actions.model.Action;
|
||||
import com.github.gumtreediff.client.Option;
|
||||
import com.github.gumtreediff.client.Register;
|
||||
import com.github.gumtreediff.io.ActionsIoUtils;
|
||||
import com.github.gumtreediff.matchers.MappingStore;
|
||||
import com.github.gumtreediff.matchers.Matcher;
|
||||
import com.github.gumtreediff.tree.TreeContext;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.PrintStream;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
@Register(name = "diff", description = "Dump actions in our textual format",
|
||||
options = AbstractDiffClient.Options.class)
|
||||
public class TextDiff extends AbstractDiffClient<TextDiff.Options> {
|
||||
|
||||
public TextDiff(String[] args) {
|
||||
super(args);
|
||||
|
||||
if (opts.format == null) {
|
||||
opts.format = OutputFormat.TEXT;
|
||||
if (opts.output != null) {
|
||||
if (opts.output.endsWith(".json"))
|
||||
opts.format = OutputFormat.JSON;
|
||||
else if (opts.output.endsWith(".xml"))
|
||||
opts.format = OutputFormat.XML;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static class Options extends AbstractDiffClient.Options {
|
||||
protected OutputFormat format;
|
||||
protected String output;
|
||||
|
||||
@Override
|
||||
public Option[] values() {
|
||||
return Option.Context.addValue(super.values(),
|
||||
new Option("-f", String.format("format: %s", Arrays.toString(OutputFormat.values())), 1) {
|
||||
@Override
|
||||
protected void process(String name, String[] args) {
|
||||
try {
|
||||
format = OutputFormat.valueOf(args[0].toUpperCase());
|
||||
} catch (IllegalArgumentException e) {
|
||||
System.err.printf("No such format '%s', available formats are: %s\n",
|
||||
args[0].toUpperCase(), Arrays.toString(OutputFormat.values()));
|
||||
System.exit(-1);
|
||||
}
|
||||
}
|
||||
},
|
||||
new Option("-o", "output file", 1) {
|
||||
@Override
|
||||
protected void process(String name, String[] args) {
|
||||
output = args[0];
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
void dump(PrintStream out) {
|
||||
super.dump(out);
|
||||
out.printf("format: %s\n", format);
|
||||
out.printf("output file: %s\n", output == null ? "<Stdout>" : output);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Options newOptions() {
|
||||
return new Options();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
Matcher m = matchTrees();
|
||||
ActionGenerator g = new ActionGenerator(getSrcTreeContext().getRoot(),
|
||||
getDstTreeContext().getRoot(), m.getMappings());
|
||||
g.generate();
|
||||
List<Action> actions = g.getActions();
|
||||
try {
|
||||
ActionsIoUtils.ActionSerializer serializer = opts.format.getSerializer(
|
||||
getSrcTreeContext(), actions, m.getMappings());
|
||||
if (opts.output == null)
|
||||
serializer.writeTo(System.out);
|
||||
else
|
||||
serializer.writeTo(opts.output);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
enum OutputFormat { // TODO make a registry for that also ?
|
||||
TEXT {
|
||||
@Override
|
||||
ActionsIoUtils.ActionSerializer getSerializer(TreeContext sctx, List<Action> actions, MappingStore mappings)
|
||||
throws IOException {
|
||||
return ActionsIoUtils.toText(sctx, actions, mappings);
|
||||
}
|
||||
},
|
||||
XML {
|
||||
@Override
|
||||
ActionsIoUtils.ActionSerializer getSerializer(TreeContext sctx, List<Action> actions, MappingStore mappings)
|
||||
throws IOException {
|
||||
return ActionsIoUtils.toXml(sctx, actions, mappings);
|
||||
}
|
||||
},
|
||||
JSON {
|
||||
@Override
|
||||
ActionsIoUtils.ActionSerializer getSerializer(TreeContext sctx, List<Action> actions, MappingStore mappings)
|
||||
throws IOException {
|
||||
return ActionsIoUtils.toJson(sctx, actions, mappings);
|
||||
}
|
||||
};
|
||||
|
||||
abstract ActionsIoUtils.ActionSerializer getSerializer(TreeContext sctx, List<Action> actions,
|
||||
MappingStore mappings) throws IOException;
|
||||
}
|
||||
}
|
||||
+204
@@ -0,0 +1,204 @@
|
||||
/*
|
||||
* This file is part of GumTree.
|
||||
*
|
||||
* GumTree is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* GumTree is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with GumTree. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Copyright 2011-2015 Jean-Rémy Falleri <jr.falleri@gmail.com>
|
||||
* Copyright 2011-2015 Floréal Morandat <florealm@gmail.com>
|
||||
*/
|
||||
|
||||
package com.github.gumtreediff.client.diff.swing;
|
||||
|
||||
import java.awt.Color;
|
||||
import java.awt.Component;
|
||||
import java.awt.Dimension;
|
||||
import java.awt.GridLayout;
|
||||
import java.io.FileReader;
|
||||
import java.io.IOException;
|
||||
|
||||
import javax.swing.JPanel;
|
||||
import javax.swing.JScrollPane;
|
||||
import javax.swing.JSplitPane;
|
||||
import javax.swing.JTextArea;
|
||||
import javax.swing.JTree;
|
||||
import javax.swing.event.TreeSelectionEvent;
|
||||
import javax.swing.event.TreeSelectionListener;
|
||||
import javax.swing.text.BadLocationException;
|
||||
import javax.swing.text.DefaultHighlighter;
|
||||
import javax.swing.tree.DefaultMutableTreeNode;
|
||||
import javax.swing.tree.DefaultTreeCellRenderer;
|
||||
import javax.swing.tree.TreePath;
|
||||
|
||||
import com.github.gumtreediff.actions.TreeClassifier;
|
||||
import com.github.gumtreediff.matchers.MappingStore;
|
||||
import com.github.gumtreediff.actions.RootsClassifier;
|
||||
import com.github.gumtreediff.matchers.Matcher;
|
||||
import com.github.gumtreediff.tree.ITree;
|
||||
import com.github.gumtreediff.tree.TreeContext;
|
||||
|
||||
public class MappingsPanel extends JPanel implements TreeSelectionListener {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private TreeContext src;
|
||||
private TreeContext dst;
|
||||
private TreeClassifier classifyTrees;
|
||||
private MappingStore mappings;
|
||||
|
||||
private TreePanel panSrc;
|
||||
private TreePanel panDst;
|
||||
private JTextArea txtSrc;
|
||||
private JTextArea txtDst;
|
||||
|
||||
private static final Color DEL_COLOR = new Color(190, 0, 0);
|
||||
private static final Color ADD_COLOR = new Color(0, 158, 0);
|
||||
private static final Color UPD_COLOR = new Color(189, 162, 0);
|
||||
//private static final Color MIS_COLOR = new Color(0, 0, 128);
|
||||
private static final Color MV_COLOR = new Color(128, 0, 128);
|
||||
|
||||
public MappingsPanel(String srcPath, String dstPath, TreeContext src, TreeContext dst, Matcher m) {
|
||||
super(new GridLayout(1, 0));
|
||||
this.src = src;
|
||||
this.dst = dst;
|
||||
this.classifyTrees = new RootsClassifier(src, dst, m);
|
||||
this.mappings = new MappingStore(m.getMappingSet());
|
||||
this.panSrc = new TreePanel(this.src, new MappingsCellRenderer(true));
|
||||
this.panSrc.getJTree().addTreeSelectionListener(this);
|
||||
this.panDst = new TreePanel(this.dst, new MappingsCellRenderer(false));
|
||||
this.panDst.getJTree().addTreeSelectionListener(this);
|
||||
this.txtSrc = new JTextArea();
|
||||
this.txtDst = new JTextArea();
|
||||
|
||||
JPanel top = new JPanel();
|
||||
top.setLayout(new GridLayout(1, 2));
|
||||
top.add(panSrc);
|
||||
top.add(panDst);
|
||||
JPanel bottom = new JPanel();
|
||||
bottom.setLayout(new GridLayout(1, 2));
|
||||
bottom.add(new JScrollPane(txtSrc));
|
||||
bottom.add(new JScrollPane(txtDst));
|
||||
|
||||
JSplitPane split = new JSplitPane(JSplitPane.VERTICAL_SPLIT, top, bottom);
|
||||
split.setDividerLocation(650);
|
||||
add(split);
|
||||
|
||||
try {
|
||||
txtSrc.getUI().getEditorKit(txtSrc).read(new FileReader(srcPath), txtSrc.getDocument(), 0);
|
||||
txtDst.getUI().getEditorKit(txtDst).read(new FileReader(dstPath), txtDst.getDocument(), 0);
|
||||
} catch (IOException | BadLocationException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
setPreferredSize(new Dimension(1024, 768));
|
||||
openNodes();
|
||||
}
|
||||
|
||||
private void openNodes() {
|
||||
for (ITree t: classifyTrees.getSrcDelTrees()) openNode(panSrc, t);
|
||||
for (ITree t: classifyTrees.getDstAddTrees()) openNode(panDst, t);
|
||||
for (ITree t: classifyTrees.getSrcUpdTrees()) openNode(panSrc, t);
|
||||
for (ITree t: classifyTrees.getDstUpdTrees()) openNode(panDst, t);
|
||||
for (ITree t: classifyTrees.getSrcMvTrees()) openNode(panSrc, t);
|
||||
for (ITree t: classifyTrees.getDstMvTrees()) openNode(panDst, t);
|
||||
panSrc.getJTree().scrollPathToVisible(new TreePath(panSrc.getTrees().get(src.getRoot()).getPath()));
|
||||
panDst.getJTree().scrollPathToVisible(new TreePath(panDst.getTrees().get(dst.getRoot()).getPath()));
|
||||
}
|
||||
|
||||
private void openNode(TreePanel p, ITree t) {
|
||||
DefaultMutableTreeNode n = p.getTrees().get(t);
|
||||
p.getJTree().scrollPathToVisible(new TreePath(n.getPath()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void valueChanged(TreeSelectionEvent e) {
|
||||
JTree jtree = (JTree) e.getSource();
|
||||
if (jtree.getSelectionPath() == null) return;
|
||||
ITree sel = (ITree) ((DefaultMutableTreeNode) jtree.getLastSelectedPathComponent()).getUserObject();
|
||||
JTextArea selJTextArea = null;
|
||||
boolean isMapped = false;
|
||||
ITree match = null;
|
||||
TreePanel matchTreePanel = null;
|
||||
JTextArea matchJTextArea = null;
|
||||
|
||||
if (jtree == panSrc.getJTree()) {
|
||||
selJTextArea = txtSrc;
|
||||
matchTreePanel = panDst;
|
||||
matchJTextArea = txtDst;
|
||||
if (mappings.hasSrc(sel)) {
|
||||
isMapped = true;
|
||||
match = mappings.getDst(sel);
|
||||
}
|
||||
} else {
|
||||
selJTextArea = txtDst;
|
||||
matchTreePanel = panSrc;
|
||||
matchJTextArea = txtSrc;
|
||||
if (mappings.hasDst(sel)) {
|
||||
isMapped = true;
|
||||
match = mappings.getSrc(sel);
|
||||
}
|
||||
}
|
||||
try {
|
||||
updateJTreeAndJTextArea(sel, selJTextArea, isMapped, match, matchTreePanel, matchJTextArea);
|
||||
} catch (BadLocationException ex) {
|
||||
ex.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
private void updateJTreeAndJTextArea(ITree sel, JTextArea selJTextArea, boolean isMapped,
|
||||
ITree match, TreePanel matchTreePanel,
|
||||
JTextArea matchJTextArea) throws BadLocationException {
|
||||
selJTextArea.getHighlighter().removeAllHighlights();
|
||||
selJTextArea.getHighlighter().addHighlight(sel.getPos(), sel.getEndPos(), DefaultHighlighter.DefaultPainter);
|
||||
selJTextArea.setCaretPosition(sel.getPos());
|
||||
|
||||
if (isMapped) {
|
||||
DefaultMutableTreeNode node = matchTreePanel.getTrees().get(match);
|
||||
matchTreePanel.getJTree().scrollPathToVisible(new TreePath(node.getPath()));
|
||||
matchTreePanel.getJTree().setSelectionPath(new TreePath(node.getPath()));
|
||||
matchJTextArea.getHighlighter().removeAllHighlights();
|
||||
matchJTextArea.getHighlighter().addHighlight(
|
||||
match.getPos(), match.getEndPos(), DefaultHighlighter.DefaultPainter);
|
||||
matchJTextArea.setCaretPosition(match.getPos());
|
||||
} else {
|
||||
matchTreePanel.getJTree().clearSelection();
|
||||
matchJTextArea.getHighlighter().removeAllHighlights();
|
||||
}
|
||||
}
|
||||
|
||||
private class MappingsCellRenderer extends DefaultTreeCellRenderer {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private boolean isSrc;
|
||||
|
||||
public MappingsCellRenderer(boolean left) {
|
||||
this.isSrc = left;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Component getTreeCellRendererComponent(JTree jtree, Object value,
|
||||
boolean selected, boolean expanded,
|
||||
boolean leaf, int row, boolean hasFocus) {
|
||||
super.getTreeCellRendererComponent(jtree, value, selected, expanded, leaf, row, hasFocus);
|
||||
ITree tree = (ITree) ((DefaultMutableTreeNode) value).getUserObject();
|
||||
if (isSrc && classifyTrees.getSrcDelTrees().contains(tree)) setForeground(DEL_COLOR);
|
||||
else if (!isSrc && classifyTrees.getDstAddTrees().contains(tree)) setForeground(ADD_COLOR);
|
||||
else if (isSrc && classifyTrees.getSrcUpdTrees().contains(tree)) setForeground(UPD_COLOR);
|
||||
else if (!isSrc && classifyTrees.getDstUpdTrees().contains(tree)) setForeground(UPD_COLOR);
|
||||
else if (isSrc && classifyTrees.getSrcMvTrees().contains(tree)) setForeground(MV_COLOR);
|
||||
else if (!isSrc && classifyTrees.getDstMvTrees().contains(tree)) setForeground(MV_COLOR);
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
+55
@@ -0,0 +1,55 @@
|
||||
/*
|
||||
* This file is part of GumTree.
|
||||
*
|
||||
* GumTree is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* GumTree is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with GumTree. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Copyright 2011-2015 Jean-Rémy Falleri <jr.falleri@gmail.com>
|
||||
* Copyright 2011-2015 Floréal Morandat <florealm@gmail.com>
|
||||
*/
|
||||
|
||||
package com.github.gumtreediff.client.diff.swing;
|
||||
|
||||
import com.github.gumtreediff.client.Register;
|
||||
import com.github.gumtreediff.client.diff.AbstractDiffClient;
|
||||
import com.github.gumtreediff.client.diff.swing.MappingsPanel;
|
||||
import com.github.gumtreediff.matchers.Matcher;
|
||||
|
||||
import javax.swing.*;
|
||||
|
||||
@Register(description = "A swing diff client", options = AbstractDiffClient.Options.class)
|
||||
public final class SwingDiff extends AbstractDiffClient<AbstractDiffClient.Options> {
|
||||
|
||||
public SwingDiff(String[] args) {
|
||||
super(args);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
final Matcher matcher = matchTrees();
|
||||
javax.swing.SwingUtilities.invokeLater(new Runnable() {
|
||||
public void run() {
|
||||
JFrame frame = new JFrame("GumTree");
|
||||
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
|
||||
frame.add(new MappingsPanel(opts.src, opts.dst, getSrcTreeContext(), getDstTreeContext(), matcher));
|
||||
frame.pack();
|
||||
frame.setVisible(true);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
protected AbstractDiffClient.Options newOptions() {
|
||||
return new AbstractDiffClient.Options();
|
||||
}
|
||||
}
|
||||
+50
@@ -0,0 +1,50 @@
|
||||
/*
|
||||
* This file is part of GumTree.
|
||||
*
|
||||
* GumTree is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* GumTree is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with GumTree. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Copyright 2011-2015 Jean-Rémy Falleri <jr.falleri@gmail.com>
|
||||
* Copyright 2011-2015 Floréal Morandat <florealm@gmail.com>
|
||||
*/
|
||||
|
||||
package com.github.gumtreediff.client.diff.swing;
|
||||
|
||||
import com.github.gumtreediff.gen.Generators;
|
||||
import com.github.gumtreediff.tree.TreeContext;
|
||||
|
||||
import javax.swing.*;
|
||||
import java.io.IOException;
|
||||
|
||||
public final class SwingTree {
|
||||
|
||||
public static void main(String[] args) throws IOException {
|
||||
final TreeContext t = Generators.getInstance().getTree(args[0]);
|
||||
javax.swing.SwingUtilities.invokeLater(new Runnable() {
|
||||
public void run() {
|
||||
createAndShow(t);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private SwingTree() {
|
||||
}
|
||||
|
||||
private static void createAndShow(TreeContext tree) {
|
||||
JFrame frame = new JFrame("Tree Viewer");
|
||||
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
|
||||
frame.add(new TreePanel(tree));
|
||||
frame.pack();
|
||||
frame.setVisible(true);
|
||||
}
|
||||
}
|
||||
+105
@@ -0,0 +1,105 @@
|
||||
/*
|
||||
* This file is part of GumTree.
|
||||
*
|
||||
* GumTree is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* GumTree is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with GumTree. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Copyright 2011-2015 Jean-Rémy Falleri <jr.falleri@gmail.com>
|
||||
* Copyright 2011-2015 Floréal Morandat <florealm@gmail.com>
|
||||
*/
|
||||
|
||||
package com.github.gumtreediff.client.diff.swing;
|
||||
|
||||
import com.github.gumtreediff.tree.ITree;
|
||||
import com.github.gumtreediff.tree.TreeContext;
|
||||
|
||||
import javax.swing.*;
|
||||
import javax.swing.event.TreeSelectionEvent;
|
||||
import javax.swing.tree.DefaultMutableTreeNode;
|
||||
import javax.swing.tree.DefaultTreeCellRenderer;
|
||||
import javax.swing.tree.TreeCellRenderer;
|
||||
import javax.swing.tree.TreeSelectionModel;
|
||||
import java.awt.*;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
public class TreePanel extends JPanel {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
private JTree jtree;
|
||||
private TreeContext tree;
|
||||
private Map<ITree, DefaultMutableTreeNode> trees;
|
||||
|
||||
public TreePanel(final TreeContext tree, TreeCellRenderer renderer) {
|
||||
super(new GridLayout(1, 0));
|
||||
trees = new HashMap<>();
|
||||
this.tree = tree;
|
||||
|
||||
ITree root = tree.getRoot();
|
||||
DefaultMutableTreeNode top = new DefaultMutableTreeNode(root);
|
||||
trees.put(root, top);
|
||||
for (ITree child: root.getChildren())
|
||||
createNodes(top, child);
|
||||
|
||||
jtree = new JTree(top) {
|
||||
private static final long serialVersionUID = 1L;
|
||||
public String convertValueToText(Object value, boolean selected,
|
||||
boolean expanded, boolean leaf, int row,
|
||||
boolean hasFocus) {
|
||||
if (value != null) {
|
||||
ITree node = ((ITree) ((DefaultMutableTreeNode) value).getUserObject());
|
||||
return node.toPrettyString(tree);
|
||||
}
|
||||
return "";
|
||||
}
|
||||
};
|
||||
jtree.setCellRenderer(renderer);
|
||||
jtree.getSelectionModel().setSelectionMode(TreeSelectionModel.SINGLE_TREE_SELECTION);
|
||||
|
||||
JScrollPane treeView = new JScrollPane(jtree);
|
||||
Dimension minimumSize = new Dimension(100, 50);
|
||||
treeView.setMinimumSize(minimumSize);
|
||||
|
||||
add(treeView);
|
||||
}
|
||||
|
||||
public TreePanel(TreeContext tree) {
|
||||
this(tree, new DefaultTreeCellRenderer());
|
||||
}
|
||||
|
||||
public JTree getJTree() {
|
||||
return jtree;
|
||||
}
|
||||
|
||||
public Map<ITree, DefaultMutableTreeNode> getTrees() {
|
||||
return trees;
|
||||
}
|
||||
|
||||
public TreeContext getTree() {
|
||||
return this.tree;
|
||||
}
|
||||
|
||||
public void valueChanged(TreeSelectionEvent e) {
|
||||
DefaultMutableTreeNode node = (DefaultMutableTreeNode) jtree.getLastSelectedPathComponent();
|
||||
if (node == null) return;
|
||||
Object nodeInfo = node.getUserObject();
|
||||
System.out.println(nodeInfo);
|
||||
}
|
||||
|
||||
private void createNodes(DefaultMutableTreeNode parent, ITree tree) {
|
||||
DefaultMutableTreeNode node = new DefaultMutableTreeNode(tree);
|
||||
trees.put(tree, node);
|
||||
parent.add(node);
|
||||
for (ITree child: tree.getChildren()) createNodes(node, child);
|
||||
}
|
||||
}
|
||||
+37
@@ -0,0 +1,37 @@
|
||||
/*
|
||||
* This file is part of GumTree.
|
||||
*
|
||||
* GumTree is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* GumTree is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with GumTree. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Copyright 2011-2015 Jean-Rémy Falleri <jr.falleri@gmail.com>
|
||||
* Copyright 2011-2015 Floréal Morandat <florealm@gmail.com>
|
||||
*/
|
||||
|
||||
package com.github.gumtreediff.client.diff.web;
|
||||
|
||||
import org.rendersnake.HtmlCanvas;
|
||||
import org.rendersnake.Renderable;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
public class BootstrapFooterView implements Renderable {
|
||||
|
||||
@Override
|
||||
public void renderOn(HtmlCanvas html) throws IOException {
|
||||
html
|
||||
.macros().javascript("/dist/jquery.min.js")
|
||||
.macros().javascript("/dist/bootstrap.min.js");
|
||||
}
|
||||
|
||||
}
|
||||
+44
@@ -0,0 +1,44 @@
|
||||
/*
|
||||
* This file is part of GumTree.
|
||||
*
|
||||
* GumTree is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* GumTree is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with GumTree. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Copyright 2011-2015 Jean-Rémy Falleri <jr.falleri@gmail.com>
|
||||
* Copyright 2011-2015 Floréal Morandat <florealm@gmail.com>
|
||||
*/
|
||||
|
||||
package com.github.gumtreediff.client.diff.web;
|
||||
|
||||
import static org.rendersnake.HtmlAttributesFactory.*;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import org.rendersnake.HtmlCanvas;
|
||||
import org.rendersnake.Renderable;
|
||||
|
||||
public class BootstrapHeaderView implements Renderable {
|
||||
|
||||
@Override
|
||||
public void renderOn(HtmlCanvas html) throws IOException {
|
||||
html
|
||||
.head()
|
||||
.meta(charset("utf8"))
|
||||
.meta(name("viewport").content("width=device-width, initial-scale=1.0"))
|
||||
.title().content("GumTree")
|
||||
.macros().stylesheet("/dist/bootstrap.min.css")
|
||||
.macros().stylesheet("/dist/gumtree.css")
|
||||
._head();
|
||||
}
|
||||
|
||||
}
|
||||
+102
@@ -0,0 +1,102 @@
|
||||
/*
|
||||
* This file is part of GumTree.
|
||||
*
|
||||
* GumTree is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* GumTree is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with GumTree. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Copyright 2011-2015 Jean-Rémy Falleri <jr.falleri@gmail.com>
|
||||
* Copyright 2011-2015 Floréal Morandat <florealm@gmail.com>
|
||||
*/
|
||||
|
||||
package com.github.gumtreediff.client.diff.web;
|
||||
|
||||
import com.github.gumtreediff.gen.Generators;
|
||||
import com.github.gumtreediff.matchers.Matcher;
|
||||
import com.github.gumtreediff.matchers.Matchers;
|
||||
import com.github.gumtreediff.tree.TreeContext;
|
||||
import org.rendersnake.DocType;
|
||||
import org.rendersnake.HtmlCanvas;
|
||||
import org.rendersnake.Renderable;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
|
||||
import static org.rendersnake.HtmlAttributesFactory.class_;
|
||||
import static org.rendersnake.HtmlAttributesFactory.lang;
|
||||
|
||||
public class DiffView implements Renderable {
|
||||
|
||||
private HtmlDiffs diffs;
|
||||
|
||||
private File fSrc;
|
||||
|
||||
private File fDst;
|
||||
|
||||
public DiffView(File fSrc, File fDst) throws IOException {
|
||||
this.fSrc = fSrc;
|
||||
this.fDst = fDst;
|
||||
TreeContext src = Generators.getInstance().getTree(fSrc.getAbsolutePath());
|
||||
TreeContext dst = Generators.getInstance().getTree(fDst.getAbsolutePath());
|
||||
Matcher matcher = Matchers.getInstance().getMatcher(src.getRoot(), dst.getRoot());
|
||||
matcher.match();
|
||||
diffs = new HtmlDiffs(fSrc, fDst, src, dst, matcher);
|
||||
diffs.produce();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void renderOn(HtmlCanvas html) throws IOException {
|
||||
html
|
||||
.render(DocType.HTML5)
|
||||
.html(lang("en"))
|
||||
.render(new BootstrapHeaderView())
|
||||
.body()
|
||||
.div(class_("container-fluid"))
|
||||
.div(class_("row"))
|
||||
.render(new MenuBar())
|
||||
._div()
|
||||
.div(class_("row"))
|
||||
.div(class_("col-lg-6 max-height"))
|
||||
.h5().content(fSrc.getName())
|
||||
.pre(class_("pre max-height")).content(diffs.getSrcDiff(), false)
|
||||
._div()
|
||||
.div(class_("col-lg-6 max-height"))
|
||||
.h5().content(fDst.getName())
|
||||
.pre(class_("pre max-height")).content(diffs.getDstDiff(), false)
|
||||
._div()
|
||||
._div()
|
||||
._div()
|
||||
.render(new BootstrapFooterView())
|
||||
.macros().javascript("/dist/diff.js")
|
||||
._body()
|
||||
._html();
|
||||
}
|
||||
|
||||
private static class MenuBar implements Renderable {
|
||||
|
||||
@Override
|
||||
public void renderOn(HtmlCanvas html) throws IOException {
|
||||
html
|
||||
.div(class_("col-lg-12"))
|
||||
.div(class_("btn-toolbar pull-right"))
|
||||
.div(class_("btn-group"))
|
||||
.a(class_("btn btn-default btn-xs").id("legend").href("#").add("data-toggle", "popover").add("data-html", "true").add("data-placement", "bottom").add("data-content", "<span class="del"> </span> deleted<br><span class="add"> </span> added<br><span class="mv"> </span> moved<br><span class="upd"> </span> updated<br>", false).add("data-original-title", "Legend").title("Legend").role("button")).content("Legend")
|
||||
.a(class_("btn btn-default btn-xs").id("shortcuts").href("#").add("data-toggle", "popover").add("data-html", "true").add("data-placement", "bottom").add("data-content", "<b>q</b> quit<br><b>l</b> list<br><b>n</b> next<br><b>t</b> top<br><b>b</b> bottom", false).add("data-original-title", "Shortcuts").title("Shortcuts").role("button")).content("Shortcuts")
|
||||
._div()
|
||||
.div(class_("btn-group"))
|
||||
.a(class_("btn btn-default btn-xs btn-danger").href("/quit")).content("Quit")
|
||||
._div()
|
||||
._div()
|
||||
._div();
|
||||
}
|
||||
}
|
||||
}
|
||||
+174
@@ -0,0 +1,174 @@
|
||||
/*
|
||||
* This file is part of GumTree.
|
||||
*
|
||||
* GumTree is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* GumTree is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with GumTree. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Copyright 2011-2015 Jean-Rémy Falleri <jr.falleri@gmail.com>
|
||||
* Copyright 2011-2015 Floréal Morandat <florealm@gmail.com>
|
||||
*/
|
||||
|
||||
package com.github.gumtreediff.client.diff.web;
|
||||
|
||||
import com.github.gumtreediff.utils.Pair;
|
||||
import com.github.gumtreediff.io.DirectoryComparator;
|
||||
import org.rendersnake.DocType;
|
||||
import org.rendersnake.HtmlCanvas;
|
||||
import org.rendersnake.Renderable;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Path;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import static org.rendersnake.HtmlAttributesFactory.*;
|
||||
|
||||
public class DirectoryComparatorView implements Renderable {
|
||||
|
||||
private DirectoryComparator comparator;
|
||||
|
||||
public DirectoryComparatorView(DirectoryComparator comparator) throws IOException {
|
||||
this.comparator = comparator;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void renderOn(HtmlCanvas html) throws IOException {
|
||||
html
|
||||
.render(DocType.HTML5)
|
||||
.html(lang("en"))
|
||||
.render(new BootstrapHeaderView())
|
||||
.body()
|
||||
.div(class_("container"))
|
||||
.div(class_("row"))
|
||||
.div(class_("col-lg-12"))
|
||||
.div(class_("panel panel-default"))
|
||||
.div(class_("panel-heading"))
|
||||
.h4(class_("panel-title"))
|
||||
.write("Modified files ")
|
||||
.span(class_("badge")).content(comparator.getModifiedFiles().size())
|
||||
._h4()
|
||||
._div()
|
||||
.div(class_("panel-body"))
|
||||
.render_if(new ModifiedFiles(comparator.getModifiedFiles()), comparator.getModifiedFiles().size() > 0)
|
||||
._div()
|
||||
._div()
|
||||
._div()
|
||||
._div()
|
||||
.div(class_("row"))
|
||||
.div(class_("col-lg-6"))
|
||||
.div(class_("panel panel-default"))
|
||||
.div(class_("panel-heading"))
|
||||
.h4(class_("panel-title"))
|
||||
.write("Deleted files ")
|
||||
.span(class_("badge")).content(comparator.getDeletedFiles().size())
|
||||
._h4()
|
||||
._div()
|
||||
.div(class_("panel-body"))
|
||||
.render_if(new AddedOrDeletedFiles(
|
||||
comparator.getDeletedFiles(), comparator.getSrc(), "danger"),
|
||||
comparator.getDeletedFiles().size() > 0)
|
||||
._div()
|
||||
._div()
|
||||
._div()
|
||||
.div(class_("col-lg-6"))
|
||||
.div(class_("panel panel-default"))
|
||||
.div(class_("panel-heading"))
|
||||
.h4(class_("panel-title"))
|
||||
.write("Added files ")
|
||||
.span(class_("badge")).content(comparator.getAddedFiles().size())
|
||||
._h4()
|
||||
._div()
|
||||
.div(class_("panel-body"))
|
||||
.render_if(new AddedOrDeletedFiles(
|
||||
comparator.getAddedFiles(), comparator.getDst(), "success"),
|
||||
comparator.getAddedFiles().size() > 0)
|
||||
._div()
|
||||
._div()
|
||||
._div()
|
||||
._div()
|
||||
._div()
|
||||
.render(new BootstrapFooterView())
|
||||
.macros().javascript("/dist/list.js")
|
||||
._body()
|
||||
._html();
|
||||
}
|
||||
|
||||
private class ModifiedFiles implements Renderable {
|
||||
|
||||
private List<Pair<File, File>> files;
|
||||
|
||||
private ModifiedFiles(List<Pair<File, File>> files) {
|
||||
this.files = files;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void renderOn(HtmlCanvas html) throws IOException {
|
||||
HtmlCanvas tbody = html
|
||||
.table(class_("table table-striped table-condensed"))
|
||||
.tbody();
|
||||
|
||||
int id = 0;
|
||||
for (Pair<File, File> file : files) {
|
||||
tbody
|
||||
.tr()
|
||||
.td(class_("col-md-10")).content(comparator.getSrc().relativize(file.getFirst().toPath()).toString())
|
||||
.td(class_("col-md-2"))
|
||||
.a(class_("btn btn-primary btn-xs").href("/diff/" + id)).content("diff")
|
||||
.write(" ")
|
||||
.a(class_("btn btn-primary btn-xs").href("/mergely/" + id)).content("mergely")
|
||||
.write(" ")
|
||||
.a(class_("btn btn-primary btn-xs").href("/script/" + id)).content("script")
|
||||
._td()
|
||||
._tr();
|
||||
id++;
|
||||
}
|
||||
tbody
|
||||
._tbody()
|
||||
._table();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private class AddedOrDeletedFiles implements Renderable {
|
||||
|
||||
private Set<File> files;
|
||||
|
||||
private Path root;
|
||||
|
||||
private String tdClass;
|
||||
|
||||
private AddedOrDeletedFiles(Set<File> files, Path root, String tdClass) {
|
||||
this.files = files;
|
||||
this.root = root;
|
||||
this.tdClass = tdClass;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void renderOn(HtmlCanvas html) throws IOException {
|
||||
HtmlCanvas tbody = html
|
||||
.table(class_("table table-condensed"))
|
||||
.tbody();
|
||||
for (File file : files) {
|
||||
tbody
|
||||
.tr()
|
||||
.td(class_(tdClass)).content(root.relativize(file.toPath()).toString())
|
||||
._tr();
|
||||
}
|
||||
tbody
|
||||
._tbody()
|
||||
._table();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
+177
@@ -0,0 +1,177 @@
|
||||
/*
|
||||
* This file is part of GumTree.
|
||||
*
|
||||
* GumTree is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* GumTree is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with GumTree. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Copyright 2011-2015 Jean-Rémy Falleri <jr.falleri@gmail.com>
|
||||
* Copyright 2011-2015 Floréal Morandat <florealm@gmail.com>
|
||||
*/
|
||||
|
||||
package com.github.gumtreediff.client.diff.web;
|
||||
|
||||
import com.github.gumtreediff.actions.RootAndLeavesClassifier;
|
||||
import com.github.gumtreediff.actions.TreeClassifier;
|
||||
import com.github.gumtreediff.utils.StringAlgorithms;
|
||||
import com.github.gumtreediff.matchers.MappingStore;
|
||||
import com.github.gumtreediff.matchers.Matcher;
|
||||
import com.github.gumtreediff.tree.ITree;
|
||||
import com.github.gumtreediff.tree.TreeContext;
|
||||
import gnu.trove.map.TIntIntMap;
|
||||
import gnu.trove.map.hash.TIntIntHashMap;
|
||||
|
||||
import java.io.*;
|
||||
import java.util.List;
|
||||
|
||||
public final class HtmlDiffs {
|
||||
|
||||
private static final String SRC_MV_SPAN = "<span class=\"%s\" id=\"move-src-%d\" data-title=\"%s\">";
|
||||
private static final String DST_MV_SPAN = "<span class=\"%s\" id=\"move-dst-%d\" data-title=\"%s\">";
|
||||
private static final String ADD_DEL_SPAN = "<span class=\"%s\" data-title=\"%s\">";
|
||||
private static final String UPD_SPAN = "<span class=\"cupd\">";
|
||||
private static final String ID_SPAN = "<span class=\"marker\" id=\"mapping-%d\"></span>";
|
||||
private static final String END_SPAN = "</span>";
|
||||
|
||||
private String srcDiff;
|
||||
|
||||
private String dstDiff;
|
||||
|
||||
private TreeContext src;
|
||||
|
||||
private TreeContext dst;
|
||||
|
||||
private File fSrc;
|
||||
|
||||
private File fDst;
|
||||
|
||||
private Matcher matcher;
|
||||
|
||||
private MappingStore mappings;
|
||||
|
||||
public HtmlDiffs(File fSrc, File fDst, TreeContext src, TreeContext dst, Matcher matcher) {
|
||||
this.fSrc = fSrc;
|
||||
this.fDst = fDst;
|
||||
this.src = src;
|
||||
this.dst = dst;
|
||||
this.matcher = matcher;
|
||||
this.mappings = matcher.getMappings();
|
||||
}
|
||||
|
||||
public void produce() throws IOException {
|
||||
TreeClassifier c = new RootAndLeavesClassifier(src, dst, matcher);
|
||||
TIntIntMap mappingIds = new TIntIntHashMap();
|
||||
|
||||
int uId = 1;
|
||||
int mId = 1;
|
||||
|
||||
TagIndex ltags = new TagIndex();
|
||||
for (ITree t: src.getRoot().getTrees()) {
|
||||
if (c.getSrcMvTrees().contains(t)) {
|
||||
mappingIds.put(mappings.getDst(t).getId(), mId);
|
||||
ltags.addStartTag(t.getPos(), String.format(ID_SPAN, uId++));
|
||||
ltags.addTags(t.getPos(), String.format(
|
||||
SRC_MV_SPAN, "token mv", mId++, tooltip(src, t)), t.getEndPos(), END_SPAN);
|
||||
}
|
||||
if (c.getSrcUpdTrees().contains(t)) {
|
||||
mappingIds.put(mappings.getDst(t).getId(), mId);
|
||||
ltags.addStartTag(t.getPos(), String.format(ID_SPAN, uId++));
|
||||
ltags.addTags(t.getPos(), String.format(
|
||||
SRC_MV_SPAN, "token upd", mId++, tooltip(src, t)), t.getEndPos(), END_SPAN);
|
||||
List<int[]> hunks = StringAlgorithms.hunks(t.getLabel(), mappings.getDst(t).getLabel());
|
||||
for (int[] hunk: hunks)
|
||||
ltags.addTags(t.getPos() + hunk[0], UPD_SPAN, t.getPos() + hunk[1], END_SPAN);
|
||||
|
||||
}
|
||||
if (c.getSrcDelTrees().contains(t)) {
|
||||
ltags.addStartTag(t.getPos(), String.format(ID_SPAN, uId++));
|
||||
ltags.addTags(t.getPos(), String.format(
|
||||
ADD_DEL_SPAN, "token del", tooltip(src, t)), t.getEndPos(), END_SPAN);
|
||||
}
|
||||
}
|
||||
|
||||
TagIndex rtags = new TagIndex();
|
||||
for (ITree t: dst.getRoot().getTrees()) {
|
||||
if (c.getDstMvTrees().contains(t)) {
|
||||
int dId = mappingIds.get(t.getId());
|
||||
rtags.addStartTag(t.getPos(), String.format(ID_SPAN, uId++));
|
||||
rtags.addTags(t.getPos(), String.format(
|
||||
DST_MV_SPAN, "token mv", dId, tooltip(dst, t)), t.getEndPos(), END_SPAN);
|
||||
}
|
||||
if (c.getDstUpdTrees().contains(t)) {
|
||||
int dId = mappingIds.get(t.getId());
|
||||
rtags.addStartTag(t.getPos(), String.format(ID_SPAN, uId++));
|
||||
rtags.addTags(t.getPos(), String.format(
|
||||
DST_MV_SPAN, "token upd", dId, tooltip(dst, t)), t.getEndPos(), END_SPAN);
|
||||
List<int[]> hunks = StringAlgorithms.hunks(mappings.getSrc(t).getLabel(), t.getLabel());
|
||||
for (int[] hunk: hunks)
|
||||
rtags.addTags(t.getPos() + hunk[2], UPD_SPAN, t.getPos() + hunk[3], END_SPAN);
|
||||
}
|
||||
if (c.getDstAddTrees().contains(t)) {
|
||||
rtags.addStartTag(t.getPos(), String.format(ID_SPAN, uId++));
|
||||
rtags.addTags(t.getPos(), String.format(
|
||||
ADD_DEL_SPAN, "token add", tooltip(dst, t)), t.getEndPos(), END_SPAN);
|
||||
}
|
||||
}
|
||||
|
||||
StringWriter w1 = new StringWriter();
|
||||
BufferedReader r = new BufferedReader(new FileReader(fSrc));
|
||||
int cursor = 0;
|
||||
|
||||
while (r.ready()) {
|
||||
char cr = (char) r.read();
|
||||
w1.append(ltags.getEndTags(cursor));
|
||||
w1.append(ltags.getStartTags(cursor));
|
||||
append(cr, w1);
|
||||
cursor++;
|
||||
}
|
||||
w1.append(ltags.getEndTags(cursor));
|
||||
r.close();
|
||||
srcDiff = w1.toString();
|
||||
|
||||
StringWriter w2 = new StringWriter();
|
||||
r = new BufferedReader(new FileReader(fDst));
|
||||
cursor = 0;
|
||||
|
||||
while (r.ready()) {
|
||||
char cr = (char) r.read();
|
||||
w2.append(rtags.getEndTags(cursor));
|
||||
w2.append(rtags.getStartTags(cursor));
|
||||
append(cr, w2);
|
||||
cursor++;
|
||||
}
|
||||
w2.append(rtags.getEndTags(cursor));
|
||||
r.close();
|
||||
|
||||
dstDiff = w2.toString();
|
||||
}
|
||||
|
||||
public String getSrcDiff() {
|
||||
return srcDiff;
|
||||
}
|
||||
|
||||
public String getDstDiff() {
|
||||
return dstDiff;
|
||||
}
|
||||
|
||||
private static String tooltip(TreeContext ctx, ITree t) {
|
||||
return (t.getParent() != null)
|
||||
? ctx.getTypeLabel(t.getParent()) + "/" + ctx.getTypeLabel(t) : ctx.getTypeLabel(t);
|
||||
}
|
||||
|
||||
private static void append(char cr, Writer w) throws IOException {
|
||||
if (cr == '<') w.append("<");
|
||||
else if (cr == '>') w.append(">");
|
||||
else if (cr == '&') w.append("&");
|
||||
else w.append(cr);
|
||||
}
|
||||
}
|
||||
+65
@@ -0,0 +1,65 @@
|
||||
/*
|
||||
* This file is part of GumTree.
|
||||
*
|
||||
* GumTree is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* GumTree is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with GumTree. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Copyright 2011-2015 Jean-Rémy Falleri <jr.falleri@gmail.com>
|
||||
* Copyright 2011-2015 Floréal Morandat <florealm@gmail.com>
|
||||
*/
|
||||
|
||||
package com.github.gumtreediff.client.diff.web;
|
||||
|
||||
import org.rendersnake.DocType;
|
||||
import org.rendersnake.HtmlCanvas;
|
||||
import org.rendersnake.Renderable;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import static org.rendersnake.HtmlAttributesFactory.*;
|
||||
|
||||
public class MergelyView implements Renderable {
|
||||
|
||||
private int id;
|
||||
|
||||
public MergelyView(int id) throws IOException {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void renderOn(HtmlCanvas html) throws IOException {
|
||||
html
|
||||
.render(DocType.HTML5)
|
||||
.html(lang("en"))
|
||||
.head()
|
||||
.meta(charset("utf8"))
|
||||
.meta(name("viewport").content("width=device-width, initial-scale=1.0"))
|
||||
.title().content("GumTree")
|
||||
.macros().javascript("/dist/jquery.min.js")
|
||||
.macros().javascript("/dist/codemirror.min.js")
|
||||
.macros().stylesheet("/dist/codemirror.css")
|
||||
.macros().javascript("/dist/mergely.min.js")
|
||||
.macros().javascript("/dist/mergely_shortcuts.js")
|
||||
.macros().stylesheet("/dist/mergely.css")
|
||||
.macros().stylesheet("/dist/mergely_custom.css")
|
||||
._head()
|
||||
.body()
|
||||
.div(id("compare"))
|
||||
._div()
|
||||
.macros().script("lhs_url = \"/left/" + id + "\";")
|
||||
.macros().script("rhs_url = \"/right/" + id + "\";")
|
||||
.macros().javascript("/dist/mergely_ajax.js")
|
||||
._body()
|
||||
._html();
|
||||
}
|
||||
}
|
||||
+93
@@ -0,0 +1,93 @@
|
||||
/*
|
||||
* This file is part of GumTree.
|
||||
*
|
||||
* GumTree is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* GumTree is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with GumTree. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Copyright 2011-2015 Jean-Rémy Falleri <jr.falleri@gmail.com>
|
||||
* Copyright 2011-2015 Floréal Morandat <florealm@gmail.com>
|
||||
*/
|
||||
|
||||
package com.github.gumtreediff.client.diff.web;
|
||||
|
||||
import com.github.gumtreediff.actions.ActionGenerator;
|
||||
import com.github.gumtreediff.actions.model.Action;
|
||||
import com.github.gumtreediff.gen.Generators;
|
||||
import com.github.gumtreediff.io.ActionsIoUtils;
|
||||
import com.github.gumtreediff.matchers.MappingStore;
|
||||
import com.github.gumtreediff.matchers.Matcher;
|
||||
import com.github.gumtreediff.matchers.Matchers;
|
||||
import com.github.gumtreediff.tree.TreeContext;
|
||||
import org.rendersnake.DocType;
|
||||
import org.rendersnake.HtmlCanvas;
|
||||
import org.rendersnake.Renderable;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
|
||||
import static org.rendersnake.HtmlAttributesFactory.class_;
|
||||
import static org.rendersnake.HtmlAttributesFactory.lang;
|
||||
|
||||
public class ScriptView implements Renderable {
|
||||
|
||||
private final MappingStore mappings;
|
||||
|
||||
private final TreeContext src;
|
||||
|
||||
private final TreeContext dst;
|
||||
|
||||
private File fSrc;
|
||||
|
||||
private File fDst;
|
||||
|
||||
private List<Action> script;
|
||||
|
||||
public ScriptView(File fSrc, File fDst) throws IOException {
|
||||
this.fSrc = fSrc;
|
||||
this.fDst = fDst;
|
||||
src = Generators.getInstance().getTree(fSrc.getAbsolutePath());
|
||||
dst = Generators.getInstance().getTree(fDst.getAbsolutePath());
|
||||
Matcher matcher = Matchers.getInstance().getMatcher(src.getRoot(), dst.getRoot());
|
||||
matcher.match();
|
||||
mappings = matcher.getMappings();
|
||||
ActionGenerator g = new ActionGenerator(src.getRoot(), dst.getRoot(), mappings);
|
||||
g.generate();
|
||||
this.script = g.getActions();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void renderOn(HtmlCanvas html) throws IOException {
|
||||
html
|
||||
.render(DocType.HTML5)
|
||||
.html(lang("en"))
|
||||
.render(new BootstrapHeaderView())
|
||||
.body()
|
||||
.div(class_("container"))
|
||||
.div(class_("row"))
|
||||
.div(class_("col-lg-12"))
|
||||
.h3()
|
||||
.write("Script ")
|
||||
.small().content(String.format("%s -> %s", fSrc.getName(), fDst.getName()))
|
||||
._h3()
|
||||
.pre().content(ActionsIoUtils.toText(src, this.script, mappings).toString())
|
||||
._div()
|
||||
._div()
|
||||
._div()
|
||||
.render(new BootstrapFooterView())
|
||||
.macros().javascript("/dist/script.js")
|
||||
._body()
|
||||
._html();
|
||||
}
|
||||
|
||||
}
|
||||
+70
@@ -0,0 +1,70 @@
|
||||
/*
|
||||
* This file is part of GumTree.
|
||||
*
|
||||
* GumTree is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* GumTree is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with GumTree. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Copyright 2011-2015 Jean-Rémy Falleri <jr.falleri@gmail.com>
|
||||
* Copyright 2011-2015 Floréal Morandat <florealm@gmail.com>
|
||||
*/
|
||||
|
||||
package com.github.gumtreediff.client.diff.web;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
public class TagIndex {
|
||||
|
||||
private Map<Integer, List<String>> startTags;
|
||||
|
||||
private Map<Integer, List<String>> endTags;
|
||||
|
||||
public TagIndex() {
|
||||
startTags = new HashMap<Integer, List<String>>();
|
||||
endTags = new HashMap<Integer, List<String>>();
|
||||
}
|
||||
|
||||
public void addTags(int pos, String startTag, int endPos, String endTag) {
|
||||
addStartTag(pos, startTag);
|
||||
addEndTag(endPos, endTag);
|
||||
}
|
||||
|
||||
public void addStartTag(int pos, String tag) {
|
||||
if (!startTags.containsKey(pos)) startTags.put(pos, new ArrayList<String>());
|
||||
startTags.get(pos).add(tag);
|
||||
}
|
||||
|
||||
public void addEndTag(int pos, String tag) {
|
||||
if (!endTags.containsKey(pos)) endTags.put(pos, new ArrayList<String>());
|
||||
endTags.get(pos).add(tag);
|
||||
}
|
||||
|
||||
public String getEndTags(int pos) {
|
||||
if (!endTags.containsKey(pos)) return "";
|
||||
StringBuffer b = new StringBuffer();
|
||||
for (String s: endTags.get(pos)) b.append(s);
|
||||
return b.toString();
|
||||
}
|
||||
|
||||
public String getStartTags(int pos) {
|
||||
if (!startTags.containsKey(pos))
|
||||
return "";
|
||||
StringBuffer b = new StringBuffer();
|
||||
for (String s: startTags.get(pos))
|
||||
b.append(s);
|
||||
return b.toString();
|
||||
}
|
||||
|
||||
}
|
||||
+150
@@ -0,0 +1,150 @@
|
||||
/*
|
||||
* This file is part of GumTree.
|
||||
*
|
||||
* GumTree is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* GumTree is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with GumTree. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Copyright 2011-2015 Jean-Rémy Falleri <jr.falleri@gmail.com>
|
||||
* Copyright 2011-2015 Floréal Morandat <florealm@gmail.com>
|
||||
*/
|
||||
|
||||
package com.github.gumtreediff.client.diff.web;
|
||||
|
||||
import com.github.gumtreediff.client.Option;
|
||||
import com.github.gumtreediff.client.Register;
|
||||
import com.github.gumtreediff.client.diff.AbstractDiffClient;
|
||||
import com.github.gumtreediff.gen.Registry;
|
||||
import com.github.gumtreediff.io.DirectoryComparator;
|
||||
import com.github.gumtreediff.utils.Pair;
|
||||
import org.rendersnake.HtmlCanvas;
|
||||
import org.rendersnake.Renderable;
|
||||
import spark.Spark;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.nio.charset.Charset;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Paths;
|
||||
|
||||
import static spark.Spark.*;
|
||||
|
||||
@Register(description = "a web diff client", options = WebDiff.Options.class, priority = Registry.Priority.HIGH)
|
||||
public class WebDiff extends AbstractDiffClient<WebDiff.Options> {
|
||||
|
||||
public WebDiff(String[] args) {
|
||||
super(args);
|
||||
}
|
||||
|
||||
static class Options extends AbstractDiffClient.Options {
|
||||
protected int defaultPort = Integer.parseInt(System.getProperty("gumtree.client.web.port", "4567"));
|
||||
boolean stdin = true;
|
||||
|
||||
@Override
|
||||
public Option[] values() {
|
||||
return Option.Context.addValue(super.values(),
|
||||
new Option("--port", String.format("set server port (default to)", defaultPort), 1) {
|
||||
@Override
|
||||
protected void process(String name, String[] args) {
|
||||
int p = Integer.parseInt(args[0]);
|
||||
if (p > 0)
|
||||
defaultPort = p;
|
||||
else
|
||||
System.err.printf("Invalid port number (%s), using %d\n", args[0], defaultPort);
|
||||
}
|
||||
},
|
||||
new Option("--no-stdin", String.format("Do not listen to stdin"), 0) {
|
||||
@Override
|
||||
protected void process(String name, String[] args) {
|
||||
stdin = false;
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Options newOptions() {
|
||||
return new Options();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
DirectoryComparator comparator = new DirectoryComparator(opts.src, opts.dst);
|
||||
comparator.compare();
|
||||
configureSpark(comparator, opts.defaultPort);
|
||||
Spark.awaitInitialization();
|
||||
System.out.println(String.format("Starting server: %s:%d", "http://127.0.0.1", opts.defaultPort));
|
||||
}
|
||||
|
||||
public static void configureSpark(final DirectoryComparator comparator, int port) {
|
||||
port(port);
|
||||
staticFiles.location("/web/");
|
||||
get("/", (request, response) -> {
|
||||
if (comparator.isDirMode())
|
||||
response.redirect("/list");
|
||||
else
|
||||
response.redirect("/diff/0");
|
||||
return "";
|
||||
});
|
||||
get("/list", (request, response) -> {
|
||||
Renderable view = new DirectoryComparatorView(comparator);
|
||||
return render(view);
|
||||
});
|
||||
get("/diff/:id", (request, response) -> {
|
||||
int id = Integer.parseInt(request.params(":id"));
|
||||
Pair<File, File> pair = comparator.getModifiedFiles().get(id);
|
||||
Renderable view = new DiffView(pair.getFirst(), pair.getSecond());
|
||||
return render(view);
|
||||
});
|
||||
get("/mergely/:id", (request, response) -> {
|
||||
int id = Integer.parseInt(request.params(":id"));
|
||||
Renderable view = new MergelyView(id);
|
||||
return render(view);
|
||||
});
|
||||
get("/left/:id", (request, response) -> {
|
||||
int id = Integer.parseInt(request.params(":id"));
|
||||
Pair<File, File> pair = comparator.getModifiedFiles().get(id);
|
||||
return readFile(pair.getFirst().getAbsolutePath(), Charset.defaultCharset());
|
||||
});
|
||||
get("/right/:id", (request, response) -> {
|
||||
int id = Integer.parseInt(request.params(":id"));
|
||||
Pair<File, File> pair = comparator.getModifiedFiles().get(id);
|
||||
return readFile(pair.getSecond().getAbsolutePath(), Charset.defaultCharset());
|
||||
});
|
||||
get("/script/:id", (request, response) -> {
|
||||
int id = Integer.parseInt(request.params(":id"));
|
||||
Pair<File, File> pair = comparator.getModifiedFiles().get(id);
|
||||
Renderable view = new ScriptView(pair.getFirst(), pair.getSecond());
|
||||
return render(view);
|
||||
});
|
||||
get("/quit", (request, response) -> {
|
||||
System.exit(0);
|
||||
return "";
|
||||
});
|
||||
}
|
||||
|
||||
private static String render(Renderable r) {
|
||||
HtmlCanvas c = new HtmlCanvas();
|
||||
try {
|
||||
r.renderOn(c);
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return c.toHtml();
|
||||
}
|
||||
|
||||
private static String readFile(String path, Charset encoding) throws IOException {
|
||||
byte[] encoded = Files.readAllBytes(Paths.get(path));
|
||||
return new String(encoded, encoding);
|
||||
}
|
||||
}
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -0,0 +1,334 @@
|
||||
/* BASICS */
|
||||
|
||||
.CodeMirror {
|
||||
/* Set height, width, borders, and global font properties here */
|
||||
font-family: monospace;
|
||||
height: 300px;
|
||||
color: black;
|
||||
}
|
||||
|
||||
/* PADDING */
|
||||
|
||||
.CodeMirror-lines {
|
||||
padding: 4px 0; /* Vertical padding around content */
|
||||
}
|
||||
.CodeMirror pre {
|
||||
padding: 0 4px; /* Horizontal padding of content */
|
||||
}
|
||||
|
||||
.CodeMirror-scrollbar-filler, .CodeMirror-gutter-filler {
|
||||
background-color: white; /* The little square between H and V scrollbars */
|
||||
}
|
||||
|
||||
/* GUTTER */
|
||||
|
||||
.CodeMirror-gutters {
|
||||
border-right: 1px solid #ddd;
|
||||
background-color: #f7f7f7;
|
||||
white-space: nowrap;
|
||||
}
|
||||
.CodeMirror-linenumbers {}
|
||||
.CodeMirror-linenumber {
|
||||
padding: 0 3px 0 5px;
|
||||
min-width: 20px;
|
||||
text-align: right;
|
||||
color: #999;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.CodeMirror-guttermarker { color: black; }
|
||||
.CodeMirror-guttermarker-subtle { color: #999; }
|
||||
|
||||
/* CURSOR */
|
||||
|
||||
.CodeMirror-cursor {
|
||||
border-left: 1px solid black;
|
||||
border-right: none;
|
||||
width: 0;
|
||||
}
|
||||
/* Shown when moving in bi-directional text */
|
||||
.CodeMirror div.CodeMirror-secondarycursor {
|
||||
border-left: 1px solid silver;
|
||||
}
|
||||
.cm-fat-cursor .CodeMirror-cursor {
|
||||
width: auto;
|
||||
border: 0;
|
||||
background: #7e7;
|
||||
}
|
||||
.cm-fat-cursor div.CodeMirror-cursors {
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
.cm-animate-fat-cursor {
|
||||
width: auto;
|
||||
border: 0;
|
||||
-webkit-animation: blink 1.06s steps(1) infinite;
|
||||
-moz-animation: blink 1.06s steps(1) infinite;
|
||||
animation: blink 1.06s steps(1) infinite;
|
||||
background-color: #7e7;
|
||||
}
|
||||
@-moz-keyframes blink {
|
||||
0% {}
|
||||
50% { background-color: transparent; }
|
||||
100% {}
|
||||
}
|
||||
@-webkit-keyframes blink {
|
||||
0% {}
|
||||
50% { background-color: transparent; }
|
||||
100% {}
|
||||
}
|
||||
@keyframes blink {
|
||||
0% {}
|
||||
50% { background-color: transparent; }
|
||||
100% {}
|
||||
}
|
||||
|
||||
/* Can style cursor different in overwrite (non-insert) mode */
|
||||
.CodeMirror-overwrite .CodeMirror-cursor {}
|
||||
|
||||
.cm-tab { display: inline-block; text-decoration: inherit; }
|
||||
|
||||
.CodeMirror-ruler {
|
||||
border-left: 1px solid #ccc;
|
||||
position: absolute;
|
||||
}
|
||||
|
||||
/* DEFAULT THEME */
|
||||
|
||||
.cm-s-default .cm-header {color: blue;}
|
||||
.cm-s-default .cm-quote {color: #090;}
|
||||
.cm-negative {color: #d44;}
|
||||
.cm-positive {color: #292;}
|
||||
.cm-header, .cm-strong {font-weight: bold;}
|
||||
.cm-em {font-style: italic;}
|
||||
.cm-link {text-decoration: underline;}
|
||||
.cm-strikethrough {text-decoration: line-through;}
|
||||
|
||||
.cm-s-default .cm-keyword {color: #708;}
|
||||
.cm-s-default .cm-atom {color: #219;}
|
||||
.cm-s-default .cm-number {color: #164;}
|
||||
.cm-s-default .cm-def {color: #00f;}
|
||||
.cm-s-default .cm-variable,
|
||||
.cm-s-default .cm-punctuation,
|
||||
.cm-s-default .cm-property,
|
||||
.cm-s-default .cm-operator {}
|
||||
.cm-s-default .cm-variable-2 {color: #05a;}
|
||||
.cm-s-default .cm-variable-3 {color: #085;}
|
||||
.cm-s-default .cm-comment {color: #a50;}
|
||||
.cm-s-default .cm-string {color: #a11;}
|
||||
.cm-s-default .cm-string-2 {color: #f50;}
|
||||
.cm-s-default .cm-meta {color: #555;}
|
||||
.cm-s-default .cm-qualifier {color: #555;}
|
||||
.cm-s-default .cm-builtin {color: #30a;}
|
||||
.cm-s-default .cm-bracket {color: #997;}
|
||||
.cm-s-default .cm-tag {color: #170;}
|
||||
.cm-s-default .cm-attribute {color: #00c;}
|
||||
.cm-s-default .cm-hr {color: #999;}
|
||||
.cm-s-default .cm-link {color: #00c;}
|
||||
|
||||
.cm-s-default .cm-error {color: #f00;}
|
||||
.cm-invalidchar {color: #f00;}
|
||||
|
||||
.CodeMirror-composing { border-bottom: 2px solid; }
|
||||
|
||||
/* Default styles for common addons */
|
||||
|
||||
div.CodeMirror span.CodeMirror-matchingbracket {color: #0f0;}
|
||||
div.CodeMirror span.CodeMirror-nonmatchingbracket {color: #f22;}
|
||||
.CodeMirror-matchingtag { background: rgba(255, 150, 0, .3); }
|
||||
.CodeMirror-activeline-background {background: #e8f2ff;}
|
||||
|
||||
/* STOP */
|
||||
|
||||
/* The rest of this file contains styles related to the mechanics of
|
||||
the editor. You probably shouldn't touch them. */
|
||||
|
||||
.CodeMirror {
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
background: white;
|
||||
}
|
||||
|
||||
.CodeMirror-scroll {
|
||||
overflow: scroll !important; /* Things will break if this is overridden */
|
||||
/* 30px is the magic margin used to hide the element's real scrollbars */
|
||||
/* See overflow: hidden in .CodeMirror */
|
||||
margin-bottom: -30px; margin-right: -30px;
|
||||
padding-bottom: 30px;
|
||||
height: 100%;
|
||||
outline: none; /* Prevent dragging from highlighting the element */
|
||||
position: relative;
|
||||
}
|
||||
.CodeMirror-sizer {
|
||||
position: relative;
|
||||
border-right: 30px solid transparent;
|
||||
}
|
||||
|
||||
/* The fake, visible scrollbars. Used to force redraw during scrolling
|
||||
before actual scrolling happens, thus preventing shaking and
|
||||
flickering artifacts. */
|
||||
.CodeMirror-vscrollbar, .CodeMirror-hscrollbar, .CodeMirror-scrollbar-filler, .CodeMirror-gutter-filler {
|
||||
position: absolute;
|
||||
z-index: 6;
|
||||
display: none;
|
||||
}
|
||||
.CodeMirror-vscrollbar {
|
||||
right: 0; top: 0;
|
||||
overflow-x: hidden;
|
||||
overflow-y: scroll;
|
||||
}
|
||||
.CodeMirror-hscrollbar {
|
||||
bottom: 0; left: 0;
|
||||
overflow-y: hidden;
|
||||
overflow-x: scroll;
|
||||
}
|
||||
.CodeMirror-scrollbar-filler {
|
||||
right: 0; bottom: 0;
|
||||
}
|
||||
.CodeMirror-gutter-filler {
|
||||
left: 0; bottom: 0;
|
||||
}
|
||||
|
||||
.CodeMirror-gutters {
|
||||
position: absolute; left: 0; top: 0;
|
||||
z-index: 3;
|
||||
}
|
||||
.CodeMirror-gutter {
|
||||
white-space: normal;
|
||||
height: 100%;
|
||||
display: inline-block;
|
||||
margin-bottom: -30px;
|
||||
/* Hack to make IE7 behave */
|
||||
*zoom:1;
|
||||
*display:inline;
|
||||
}
|
||||
.CodeMirror-gutter-wrapper {
|
||||
position: absolute;
|
||||
z-index: 4;
|
||||
background: none !important;
|
||||
border: none !important;
|
||||
}
|
||||
.CodeMirror-gutter-background {
|
||||
position: absolute;
|
||||
top: 0; bottom: 0;
|
||||
z-index: 4;
|
||||
}
|
||||
.CodeMirror-gutter-elt {
|
||||
position: absolute;
|
||||
cursor: default;
|
||||
z-index: 4;
|
||||
}
|
||||
.CodeMirror-gutter-wrapper {
|
||||
-webkit-user-select: none;
|
||||
-moz-user-select: none;
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
.CodeMirror-lines {
|
||||
cursor: text;
|
||||
min-height: 1px; /* prevents collapsing before first draw */
|
||||
}
|
||||
.CodeMirror pre {
|
||||
/* Reset some styles that the rest of the page might have set */
|
||||
-moz-border-radius: 0; -webkit-border-radius: 0; border-radius: 0;
|
||||
border-width: 0;
|
||||
background: transparent;
|
||||
font-family: inherit;
|
||||
font-size: inherit;
|
||||
margin: 0;
|
||||
white-space: pre;
|
||||
word-wrap: normal;
|
||||
line-height: inherit;
|
||||
color: inherit;
|
||||
z-index: 2;
|
||||
position: relative;
|
||||
overflow: visible;
|
||||
-webkit-tap-highlight-color: transparent;
|
||||
}
|
||||
.CodeMirror-wrap pre {
|
||||
word-wrap: break-word;
|
||||
white-space: pre-wrap;
|
||||
word-break: normal;
|
||||
}
|
||||
|
||||
.CodeMirror-linebackground {
|
||||
position: absolute;
|
||||
left: 0; right: 0; top: 0; bottom: 0;
|
||||
z-index: 0;
|
||||
}
|
||||
|
||||
.CodeMirror-linewidget {
|
||||
position: relative;
|
||||
z-index: 2;
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
.CodeMirror-widget {}
|
||||
|
||||
.CodeMirror-code {
|
||||
outline: none;
|
||||
}
|
||||
|
||||
/* Force content-box sizing for the elements where we expect it */
|
||||
.CodeMirror-scroll,
|
||||
.CodeMirror-sizer,
|
||||
.CodeMirror-gutter,
|
||||
.CodeMirror-gutters,
|
||||
.CodeMirror-linenumber {
|
||||
-moz-box-sizing: content-box;
|
||||
box-sizing: content-box;
|
||||
}
|
||||
|
||||
.CodeMirror-measure {
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
height: 0;
|
||||
overflow: hidden;
|
||||
visibility: hidden;
|
||||
}
|
||||
|
||||
.CodeMirror-cursor { position: absolute; }
|
||||
.CodeMirror-measure pre { position: static; }
|
||||
|
||||
div.CodeMirror-cursors {
|
||||
visibility: hidden;
|
||||
position: relative;
|
||||
z-index: 3;
|
||||
}
|
||||
div.CodeMirror-dragcursors {
|
||||
visibility: visible;
|
||||
}
|
||||
|
||||
.CodeMirror-focused div.CodeMirror-cursors {
|
||||
visibility: visible;
|
||||
}
|
||||
|
||||
.CodeMirror-selected { background: #d9d9d9; }
|
||||
.CodeMirror-focused .CodeMirror-selected { background: #d7d4f0; }
|
||||
.CodeMirror-crosshair { cursor: crosshair; }
|
||||
.CodeMirror-line::selection, .CodeMirror-line > span::selection, .CodeMirror-line > span > span::selection { background: #d7d4f0; }
|
||||
.CodeMirror-line::-moz-selection, .CodeMirror-line > span::-moz-selection, .CodeMirror-line > span > span::-moz-selection { background: #d7d4f0; }
|
||||
|
||||
.cm-searching {
|
||||
background: #ffa;
|
||||
background: rgba(255, 255, 0, .4);
|
||||
}
|
||||
|
||||
/* IE7 hack to prevent it from returning funny offsetTops on the spans */
|
||||
.CodeMirror span { *vertical-align: text-bottom; }
|
||||
|
||||
/* Used to force a border model for a node */
|
||||
.cm-force-border { padding-right: .1px; }
|
||||
|
||||
@media print {
|
||||
/* Hide the cursor when printing */
|
||||
.CodeMirror div.CodeMirror-cursors {
|
||||
visibility: hidden;
|
||||
}
|
||||
}
|
||||
|
||||
/* See issue #2901 */
|
||||
.cm-tab-wrap-hack:after { content: ''; }
|
||||
|
||||
/* Help users use markselection to safely style text background */
|
||||
span.CodeMirror-selectedtext { background: none; }
|
||||
File diff suppressed because one or more lines are too long
@@ -0,0 +1,120 @@
|
||||
/*
|
||||
* This file is part of GumTree.
|
||||
*
|
||||
* GumTree is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* GumTree is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with GumTree. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Copyright 2011-2015 Jean-Rémy Falleri <jr.falleri@gmail.com>
|
||||
* Copyright 2011-2015 Floréal Morandat <florealm@gmail.com>
|
||||
*/
|
||||
|
||||
currentMapping = 0;
|
||||
|
||||
if (typeof String.prototype.startsWith != 'function') {
|
||||
String.prototype.startsWith = function (str){
|
||||
return this.slice(0, str.length) == str;
|
||||
};
|
||||
}
|
||||
|
||||
function getMappedElement(eltId) {
|
||||
if (eltId.startsWith("move-src")) {
|
||||
return eltId.replace("src","dst");
|
||||
}
|
||||
else {
|
||||
return eltId.replace("dst","src");
|
||||
}
|
||||
}
|
||||
|
||||
function nextMapping() {
|
||||
if (currentMapping == 0) {
|
||||
currentMapping = 1;
|
||||
return "#mapping-" + currentMapping.toString();
|
||||
} else {
|
||||
currentMapping++;
|
||||
|
||||
if ($("#mapping-" + currentMapping.toString()).length > 0) {
|
||||
return "#mapping-" + currentMapping.toString();
|
||||
} else {
|
||||
currentMapping = 1;
|
||||
return "#mapping-" + currentMapping.toString();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function isSrc(eltId) {
|
||||
return eltId.startsWith("move-src");
|
||||
}
|
||||
|
||||
$(function() {
|
||||
$("#legend").popover();
|
||||
|
||||
$("#shortcuts").popover();
|
||||
|
||||
// shortcuts
|
||||
$("body").keypress(function (event) {
|
||||
switch(event.which) {
|
||||
case 110:
|
||||
var mapping = nextMapping();
|
||||
$('html, body').animate({scrollTop: $(mapping).offset().top - 200}, 100);
|
||||
break;
|
||||
case 116:
|
||||
$('html, body').animate({scrollTop: 0}, 100);
|
||||
break;
|
||||
case 98:
|
||||
$("html, body").animate({ scrollTop: $(document).height() }, 100);
|
||||
break;
|
||||
case 113:
|
||||
window.location = "/quit";
|
||||
break;
|
||||
case 108:
|
||||
window.location = "/list";
|
||||
break;
|
||||
}
|
||||
});
|
||||
|
||||
// highlight
|
||||
$("span.mv.token, span.token.upd").click(function(event) {
|
||||
if ($(this).hasClass("selected")) {
|
||||
$("span.mv.token, span.token.upd").removeClass("selected");
|
||||
} else {
|
||||
$("span.mv.token, span.token.upd").removeClass("selected");
|
||||
var eltId = $(this).attr("id");
|
||||
var refEltId = getMappedElement(eltId);
|
||||
$("#" + refEltId).addClass("selected");
|
||||
$(this).addClass("selected");
|
||||
var sel = "#dst";
|
||||
if (isSrc(refEltId))
|
||||
var sel = "#src";
|
||||
$div = $(sel);
|
||||
$span = $("#" + refEltId);
|
||||
}
|
||||
event.stopPropagation();
|
||||
});
|
||||
|
||||
$("span.add.token, span.token.del").click(function(event) {
|
||||
$("span.mv.token, span.token.upd").removeClass("selected");
|
||||
event.stopPropagation();
|
||||
});
|
||||
|
||||
// tooltip
|
||||
$("span.token").hover(
|
||||
function (event) {
|
||||
$(this).tooltip('show');
|
||||
event.stopPropagation();
|
||||
},
|
||||
function (event) {
|
||||
$(this).tooltip('hide');
|
||||
event.stopPropagation();
|
||||
}
|
||||
);
|
||||
});
|
||||
@@ -0,0 +1,93 @@
|
||||
/*
|
||||
* This file is part of GumTree.
|
||||
*
|
||||
* GumTree is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* GumTree is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with GumTree. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Copyright 2011-2015 Jean-Rémy Falleri <jr.falleri@gmail.com>
|
||||
* Copyright 2011-2015 Floréal Morandat <florealm@gmail.com>
|
||||
*/
|
||||
|
||||
.add {
|
||||
border: 1px solid black;
|
||||
background-color: MediumSeaGreen;
|
||||
}
|
||||
|
||||
.del {
|
||||
border: 1px solid black;
|
||||
background-color: DarkSalmon;
|
||||
}
|
||||
|
||||
.mv {
|
||||
border: 1px solid black;
|
||||
background-color: Lavender;
|
||||
}
|
||||
|
||||
.upd {
|
||||
border: 1px solid black;
|
||||
background-color: RosyBrown;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.cupd {
|
||||
font-weight: normal;
|
||||
color: DimGray;
|
||||
}
|
||||
|
||||
.selected {
|
||||
background-color: Gold;
|
||||
}
|
||||
|
||||
.marker {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.container {
|
||||
margin-right: auto;
|
||||
margin-left: auto;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.scrollable {
|
||||
overflow: scroll;
|
||||
}
|
||||
|
||||
.no-overflow {
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
body, html {
|
||||
height: 100%;
|
||||
margin: 0px;
|
||||
padding: 0px;
|
||||
}
|
||||
|
||||
div {
|
||||
margin: 0px;
|
||||
padding: 0px;
|
||||
}
|
||||
|
||||
.max-height {
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.pre {
|
||||
margin: 0px;
|
||||
padding: 0px;
|
||||
font-size: 10pt;
|
||||
color: black;
|
||||
background-color: white;
|
||||
border-color: black;
|
||||
font-family: "Inconsolata", "Consolas", "Liberation Sans Regular", "DejaVu Sans Mono", monospace;
|
||||
}
|
||||
File diff suppressed because one or more lines are too long
@@ -0,0 +1,31 @@
|
||||
/*
|
||||
* This file is part of GumTree.
|
||||
*
|
||||
* GumTree is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* GumTree is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with GumTree. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Copyright 2011-2015 Jean-Rémy Falleri <jr.falleri@gmail.com>
|
||||
* Copyright 2011-2015 Floréal Morandat <florealm@gmail.com>
|
||||
*/
|
||||
|
||||
$(function() {
|
||||
// shortcut
|
||||
$("body").keypress(function (event) {
|
||||
switch (event.which) {
|
||||
case 113:
|
||||
window.location = "/quit";
|
||||
break;
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
@@ -0,0 +1,50 @@
|
||||
/**
|
||||
* Copyright (c) 2016 by Jamie Peabody, http://www.mergely.com
|
||||
* All rights reserved.
|
||||
* Version: 3.4.3 2016-09-07
|
||||
*/
|
||||
|
||||
/* required */
|
||||
.mergely-column textarea { width: 80px; height: 200px; }
|
||||
.mergely-column { float: left; }
|
||||
.mergely-margin { float: left; }
|
||||
.mergely-canvas { float: left; width: 28px; }
|
||||
|
||||
/* resizeable */
|
||||
.mergely-resizer { width: 100%; height: 100%; }
|
||||
|
||||
/* style configuration */
|
||||
.mergely-column { border: 1px solid #ccc; }
|
||||
.mergely-active { border: 1px solid #a3d1ff; }
|
||||
|
||||
.mergely.a,.mergely.d,.mergely.c { color: #000; }
|
||||
|
||||
.mergely.a.rhs.start { border-top: 1px solid #a3d1ff; }
|
||||
.mergely.a.lhs.start.end,
|
||||
.mergely.a.rhs.end { border-bottom: 1px solid #a3d1ff; }
|
||||
.mergely.a.rhs { background-color: #ddeeff; }
|
||||
.mergely.a.lhs.start.end.first { border-bottom: 0; border-top: 1px solid #a3d1ff; }
|
||||
|
||||
.mergely.d.lhs { background-color: #ffe9e9; }
|
||||
.mergely.d.lhs.end,
|
||||
.mergely.d.rhs.start.end { border-bottom: 1px solid #f8e8e8; }
|
||||
.mergely.d.rhs.start.end.first { border-bottom: 0; border-top: 1px solid #f8e8e8; }
|
||||
.mergely.d.lhs.start { border-top: 1px solid #f8e8e8; }
|
||||
|
||||
.mergely.c.lhs,
|
||||
.mergely.c.rhs { background-color: #fafafa; }
|
||||
.mergely.c.lhs.start,
|
||||
.mergely.c.rhs.start { border-top: 1px solid #a3a3a3; }
|
||||
.mergely.c.lhs.end,
|
||||
.mergely.c.rhs.end { border-bottom: 1px solid #a3a3a3; }
|
||||
|
||||
.mergely.ch.a.rhs { background-color: #ddeeff; }
|
||||
.mergely.ch.d.lhs { background-color: #ffe9e9; text-decoration: line-through; color: red !important; }
|
||||
|
||||
.mergely.current.start { border-top: 1px solid #000 !important; }
|
||||
.mergely.current.end { border-bottom: 1px solid #000 !important; }
|
||||
.mergely.current.lhs.a.start.end,
|
||||
.mergely.current.rhs.d.start.end { border-top: 0 !important; }
|
||||
.mergely.current.CodeMirror-linenumber { color: #F9F9F9; font-weight: bold; background-color: #777; }
|
||||
.CodeMirror-linenumber { cursor: pointer; }
|
||||
.CodeMirror-code { color: #717171; }
|
||||
File diff suppressed because one or more lines are too long
@@ -0,0 +1,19 @@
|
||||
$(document).ready(function () {
|
||||
$('#compare').mergely({
|
||||
editor_width: 'calc(50% - 25px)',
|
||||
editor_height: 'calc(100% - 25px)',
|
||||
cmsettings: {
|
||||
readOnly: true,
|
||||
lineNumbers: true,
|
||||
lineWrapping: true
|
||||
}
|
||||
});
|
||||
|
||||
$.get(lhs_url, function(data) {
|
||||
$('#compare').mergely('lhs', data);
|
||||
});
|
||||
|
||||
$.get(rhs_url, function(data) {
|
||||
$('#compare').mergely('rhs', data);
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,8 @@
|
||||
html, body, #compare, .CodeMirror {
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.CodeMirror pre {
|
||||
font-family: "Inconsolata", "Consolas", "Liberation Sans Regular", "DejaVu Sans Mono", monospace;
|
||||
font-size: 10pt;
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
/*
|
||||
* This file is part of GumTree.
|
||||
*
|
||||
* GumTree is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* GumTree is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with GumTree. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Copyright 2016 Floréal Morandat <florealm@gmail.com>
|
||||
*/
|
||||
|
||||
$(function(){
|
||||
$("body").keypress(function (event) {
|
||||
switch (event.which) {
|
||||
case 113:
|
||||
window.location = "/quit";
|
||||
break;
|
||||
case 108:
|
||||
window.location = "/list";
|
||||
break;
|
||||
}
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,40 @@
|
||||
/*
|
||||
* This file is part of GumTree.
|
||||
*
|
||||
* GumTree is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* GumTree is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with GumTree. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Copyright 2011-2015 Jean-Rémy Falleri <jr.falleri@gmail.com>
|
||||
* Copyright 2011-2015 Floréal Morandat <florealm@gmail.com>
|
||||
*/
|
||||
|
||||
$(function(){
|
||||
$("#infos").popover();
|
||||
|
||||
$("body").keypress(function (event) {
|
||||
switch (event.which) {
|
||||
case 116:
|
||||
$('html, body').animate({scrollTop: 0}, 100);
|
||||
break;
|
||||
case 98:
|
||||
$("html, body").animate({ scrollTop: $(document).height() }, 100);
|
||||
break;
|
||||
case 113:
|
||||
window.location = "/quit";
|
||||
break;
|
||||
case 108:
|
||||
window.location = "/list";
|
||||
break;
|
||||
}
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user