{@link #getOriginalFile()}
, depending on how the external
57 | * tool works.
58 | * 59 | * A good example is an external tool that can only process C++ source files 60 | * but not header files. If the original file is a header file, the 61 | * checker could potentially find a C++ file that includes such header and 62 | * use it as the actual file to process. 63 | *
64 | *65 | * We still need to keep a reference to the actual file, in order 66 | * to add markers to the editor in case of problems found. 67 | *
68 | * 69 | * @return the actual file to process. 70 | */ 71 | public IResource getActualFile() { 72 | return actualFile; 73 | } 74 | 75 | /** 76 | * Returns the path of{@link #getActualFile()}
, in a format
77 | * the external tool can understand.
78 | *
79 | * @return the path of the actual file to process.
80 | */
81 | public String getActualFilePath() {
82 | return actualFilePath;
83 | }
84 |
85 | /**
86 | * Returns the directory where the external tool should be executed.
87 | *
88 | * @return the directory where the external tool should be executed.
89 | */
90 | public IPath getWorkingDirectory() {
91 | return workingDirectory;
92 | }
93 |
94 | public CppStyleMessageConsole getConsole() {
95 | return console;
96 | }
97 | }
98 |
--------------------------------------------------------------------------------
/plugin/src/org/wangzw/plugin/cppstyle/ui/CppStyleConsolePage.java:
--------------------------------------------------------------------------------
1 | package org.wangzw.plugin.cppstyle.ui;
2 |
3 | import org.eclipse.debug.internal.ui.views.console.ShowStandardErrorAction;
4 | import org.eclipse.debug.internal.ui.views.console.ShowStandardOutAction;
5 | import org.eclipse.debug.internal.ui.views.console.ShowWhenContentChangesAction;
6 | import org.eclipse.jface.action.IMenuManager;
7 | import org.eclipse.jface.action.IToolBarManager;
8 | import org.eclipse.swt.widgets.Composite;
9 | import org.eclipse.ui.actions.ActionFactory;
10 | import org.eclipse.ui.console.IConsoleConstants;
11 | import org.eclipse.ui.console.IConsoleView;
12 | import org.eclipse.ui.console.TextConsolePage;
13 | import org.eclipse.ui.console.TextConsoleViewer;
14 |
15 | public class CppStyleConsolePage extends TextConsolePage {
16 | private CppStyleConsoleViewer viewer = null;
17 | private CppStyleMessageConsole console = null;
18 | private ShowWhenContentChangesAction fStdOut;
19 | private ShowWhenContentChangesAction fStdErr;
20 |
21 | public CppStyleConsolePage(CppStyleMessageConsole console, IConsoleView view) {
22 | super(console, view);
23 | this.console = console;
24 | }
25 |
26 | @Override
27 | public void dispose() {
28 | super.dispose();
29 |
30 | if (fStdOut != null) {
31 | fStdOut.dispose();
32 | fStdOut = null;
33 | }
34 | if (fStdErr != null) {
35 | fStdErr.dispose();
36 | fStdErr = null;
37 | }
38 | }
39 |
40 | @Override
41 | protected TextConsoleViewer createViewer(Composite parent) {
42 | viewer = new CppStyleConsoleViewer(parent, console);
43 | return viewer;
44 | }
45 |
46 | @Override
47 | protected void contextMenuAboutToShow(IMenuManager menuManager) {
48 | super.contextMenuAboutToShow(menuManager);
49 | menuManager.remove(ActionFactory.CUT.getId());
50 | menuManager.remove(ActionFactory.PASTE.getId());
51 | }
52 |
53 | @Override
54 | protected void configureToolBar(IToolBarManager mgr) {
55 | super.configureToolBar(mgr);
56 | fStdOut = new ShowStandardOutAction();
57 | fStdErr = new ShowStandardErrorAction();
58 | mgr.appendToGroup(IConsoleConstants.OUTPUT_GROUP, fStdOut);
59 | mgr.appendToGroup(IConsoleConstants.OUTPUT_GROUP, fStdErr);
60 | }
61 |
62 | public boolean activeOnStdout() {
63 | if (fStdOut == null || !fStdOut.isChecked()) {
64 | return false;
65 | }
66 |
67 | return true;
68 | }
69 |
70 | public boolean activeOnStderr() {
71 | if (fStdErr == null || !fStdErr.isChecked()) {
72 | return false;
73 | }
74 |
75 | return true;
76 | }
77 |
78 | }
79 |
--------------------------------------------------------------------------------
/plugin/src/org/wangzw/plugin/cppstyle/ui/CppStyleConsolePatternMatchListener.java:
--------------------------------------------------------------------------------
1 | package org.wangzw.plugin.cppstyle.ui;
2 |
3 | import java.util.regex.Matcher;
4 | import java.util.regex.Pattern;
5 |
6 | import org.eclipse.core.resources.IFile;
7 | import org.eclipse.debug.ui.console.FileLink;
8 | import org.eclipse.jface.text.BadLocationException;
9 | import org.eclipse.ui.console.IPatternMatchListener;
10 | import org.eclipse.ui.console.PatternMatchEvent;
11 | import org.eclipse.ui.console.TextConsole;
12 | import org.wangzw.plugin.cppstyle.CppStyle;
13 |
14 | public class CppStyleConsolePatternMatchListener implements IPatternMatchListener {
15 |
16 | private IFile file = null;
17 | private Pattern pattern = null;
18 | private int lineNumGroup = CppStyleConstants.CPPLINT_OUTPUT_PATTERN_LINE_NO_GROUP;
19 | private String patternMsg = CppStyleConstants.CPPLINT_OUTPUT_PATTERN;
20 |
21 | public IFile getFile() {
22 | return file;
23 | }
24 |
25 | public void setFile(IFile file) {
26 | this.file = file;
27 | }
28 |
29 | @Override
30 | public void connect(TextConsole console) {
31 | pattern = Pattern.compile(patternMsg);
32 | }
33 |
34 | @Override
35 | public void disconnect() {
36 | }
37 |
38 | @Override
39 | public String getPattern() {
40 | return patternMsg;
41 | }
42 |
43 | @Override
44 | public int getCompilerFlags() {
45 | return 0;
46 | }
47 |
48 | @Override
49 | public String getLineQualifier() {
50 | return "\\n|\\r";
51 | }
52 |
53 | @Override
54 | public void matchFound(PatternMatchEvent event) {
55 | try {
56 | CppStyleMessageConsole console = (CppStyleMessageConsole) event.getSource();
57 |
58 | String line = console.getDocument().get(event.getOffset(), event.getLength());
59 |
60 | Matcher m = pattern.matcher(line);
61 | if (m.matches()) {
62 | String ln = m.group(lineNumGroup);
63 |
64 | int lineno = Integer.parseInt(ln);
65 |
66 | FileLink link = new FileLink(file, null, -1, -1, lineno == 0 ? 1 : lineno);
67 | console.addFileLink(link, event.getOffset(), event.getLength());
68 | }
69 | } catch (BadLocationException e) {
70 | CppStyle.log("Failed to add link", e);
71 | }
72 | }
73 | }
74 |
--------------------------------------------------------------------------------
/plugin/src/org/wangzw/plugin/cppstyle/ui/CppStyleConsoleViewer.java:
--------------------------------------------------------------------------------
1 | package org.wangzw.plugin.cppstyle.ui;
2 |
3 | import org.eclipse.debug.ui.console.FileLink;
4 | import org.eclipse.jface.text.BadPositionCategoryException;
5 | import org.eclipse.jface.text.DocumentEvent;
6 | import org.eclipse.jface.text.IDocumentListener;
7 | import org.eclipse.jface.text.Position;
8 | import org.eclipse.swt.custom.StyledText;
9 | import org.eclipse.swt.events.MouseEvent;
10 | import org.eclipse.swt.graphics.Point;
11 | import org.eclipse.swt.widgets.Composite;
12 | import org.eclipse.swt.widgets.Control;
13 | import org.eclipse.ui.console.ConsolePlugin;
14 | import org.eclipse.ui.console.TextConsoleViewer;
15 | import org.wangzw.plugin.cppstyle.CppStyle;
16 |
17 | public class CppStyleConsoleViewer extends TextConsoleViewer {
18 | private CppStyleMessageConsole console = null;
19 |
20 | private IDocumentListener documentListener = new IDocumentListener() {
21 | @Override
22 | public void documentAboutToBeChanged(DocumentEvent event) {
23 | }
24 |
25 | @Override
26 | public void documentChanged(DocumentEvent event) {
27 | clearFileLink();
28 | }
29 | };
30 |
31 | public CppStyleConsoleViewer(Composite parent, CppStyleMessageConsole console) {
32 | super(parent, console);
33 | this.console = console;
34 | this.getDocument().addDocumentListener(documentListener);
35 | }
36 |
37 | @Override
38 | protected void createControl(Composite parent, int styles) {
39 | super.createControl(parent, styles);
40 | setReadOnly();
41 | Control control = getTextWidget();
42 | control.addMouseListener(this);
43 | }
44 |
45 | @Override
46 | public void mouseDoubleClick(MouseEvent e) {
47 | StyledText widget = getTextWidget();
48 | if (widget != null) {
49 | int offset = -1;
50 | try {
51 | Point p = new Point(e.x, e.y);
52 | offset = widget.getOffsetAtLocation(p);
53 | FileLink link = getFileLink(offset);
54 |
55 | if (link != null) {
56 | link.linkActivated();
57 | }
58 |
59 | } catch (IllegalArgumentException ex) {
60 | }
61 | }
62 | }
63 |
64 | @Override
65 | protected void handleDispose() {
66 | Control control = getTextWidget();
67 |
68 | if (control != null) {
69 | control.removeMouseListener(this);
70 | }
71 |
72 | this.getDocument().removeDocumentListener(documentListener);
73 | super.handleDispose();
74 | }
75 |
76 | /**
77 | * makes the associated text widget uneditable.
78 | */
79 | public void setReadOnly() {
80 | ConsolePlugin.getStandardDisplay().asyncExec(new Runnable() {
81 | @Override
82 | public void run() {
83 | StyledText text = getTextWidget();
84 | if (text != null && !text.isDisposed()) {
85 | text.setEditable(false);
86 | }
87 | }
88 | });
89 | }
90 |
91 | public FileLink getFileLink(int offset) {
92 | if (offset >= 0 && console != null) {
93 | return console.getFileLink(offset);
94 | }
95 | return null;
96 | }
97 |
98 | public void clearFileLink() {
99 | try {
100 | Position[] positions = getDocument().getPositions(CppStyleMessageConsole.ERROR_MARKER_CATEGORY);
101 |
102 | for (Position position : positions) {
103 | getDocument().removePosition(CppStyleMessageConsole.ERROR_MARKER_CATEGORY, position);
104 | }
105 | } catch (BadPositionCategoryException e) {
106 | CppStyle.log(e);
107 | }
108 | }
109 | }
110 |
--------------------------------------------------------------------------------
/plugin/src/org/wangzw/plugin/cppstyle/ui/CppStyleConstants.java:
--------------------------------------------------------------------------------
1 | package org.wangzw.plugin.cppstyle.ui;
2 |
3 | /**
4 | * Constant definitions for plug-in
5 | */
6 | public class CppStyleConstants {
7 | public static final String PerfPageId = "org.wangzw.plugin.cppstyle.ui.CppStylePerfPage";
8 |
9 | public static final String CLANG_FORMAT_PATH = "cppstyle.clangformat.path";
10 | public static final String CPPLINT_PATH = "cppstyle.cpplint.path";
11 | public static final String ENABLE_CPPLINT_ON_SAVE = "cppstyle.enable.cpplint.on.save";
12 | public static final String ENABLE_CLANGFORMAT_ON_SAVE = "cppstyle.enable.clangformat.on.save";
13 |
14 | public static final String ENABLE_CPPLINT_TEXT = "Enable cpplint";
15 | public static final String ENABLE_CLANGFORMAT_TEXT = "Run clang-format on file save";
16 | public static final String PROJECT_ROOT_TEXT = "Select root path for cpplint (optional):";
17 |
18 | public static final String PROJECTS_PECIFIC_PROPERTY = "cppstyle.ENABLE_PROJECTS_PECIFIC";
19 | public static final String ENABLE_CPPLINT_PROPERTY = "cppstyle.ENABLE_CPPLINT";
20 | public static final String ENABLE_CLANGFORMAT_PROPERTY = "cppstyle.ENABLE_CLANGFORMAT";
21 | public static final String CPPLINT_PROJECT_ROOT = "cppstyle.PROJECT_ROOT";
22 |
23 | public static final String CPPLINT_MARKER = "org.wangzw.plugin.cppstyle.CpplintMarker";
24 | public static final String CONSOLE_NAME = "CppStyle Output";
25 | public static final String CPPLINT_CONSOLE_PREFIX = "cpplint.py: ";
26 | public static final String CPPLINT_OUTPUT_PATTERN = "(.+)\\:(\\d+)\\:(.+)\\[(.+)/(.+)\\](.*)\\[(\\d)\\]";
27 | public static final int CPPLINT_OUTPUT_PATTERN_PATH_GROUP = 1;
28 | public static final int CPPLINT_OUTPUT_PATTERN_LINE_NO_GROUP = 2;
29 | public static final int CPPLINT_OUTPUT_PATTERN_MSG_GROUP = 3;
30 | public static final int CPPLINT_OUTPUT_PATTERN_CATEGORY_GROUP = 4;
31 | public static final int CPPLINT_OUTPUT_PATTERN_CATEGORY_SUBGROUP = 5;
32 | public static final int CPPLINT_OUTPUT_PATTERN_SEVERITY_GROUP = 7;
33 |
34 | public static final String CPPLINT_OUTPUT_PARSER_ID = "org.wangzw.plugin.cppstyle.CpplintErrorParser";
35 | public static final String CPPLINT_PROBLEM_ID_KEY = "id";
36 | public static final String CPPLINT_ERROR_PROBLEM_ID = "org.wangzw.plugin.cppstyle.cpplint.build.categorized";
37 | }
38 |
--------------------------------------------------------------------------------
/plugin/src/org/wangzw/plugin/cppstyle/ui/CppStyleHandler.java:
--------------------------------------------------------------------------------
1 | package org.wangzw.plugin.cppstyle.ui;
2 |
3 | import org.eclipse.cdt.ui.ICEditor;
4 | import org.eclipse.core.commands.ExecutionEvent;
5 | import org.eclipse.core.commands.ExecutionException;
6 | import org.eclipse.core.expressions.EvaluationResult;
7 | import org.eclipse.core.expressions.IEvaluationContext;
8 | import org.eclipse.core.resources.IFile;
9 | import org.eclipse.ui.IFileEditorInput;
10 | import org.eclipse.ui.ISaveablePart;
11 | import org.eclipse.ui.ISaveablesSource;
12 | import org.eclipse.ui.IWorkbenchPage;
13 | import org.eclipse.ui.IWorkbenchPart;
14 | import org.eclipse.ui.IWorkbenchWindow;
15 | import org.eclipse.ui.handlers.HandlerUtil;
16 | import org.eclipse.ui.internal.InternalHandlerUtil;
17 | import org.eclipse.ui.internal.SaveableHelper;
18 | import org.eclipse.ui.internal.WorkbenchPage;
19 | import org.eclipse.ui.internal.handlers.AbstractSaveHandler;
20 | import org.wangzw.plugin.cppstyle.ClangFormatFormatter;
21 |
22 | /**
23 | * Our sample handler extends AbstractHandler, an IHandler base class.
24 | *
25 | * @see org.eclipse.core.commands.IHandler
26 | * @see org.eclipse.core.commands.AbstractHandler
27 | */
28 | public class CppStyleHandler extends AbstractSaveHandler {
29 | /**
30 | * The constructor.
31 | */
32 | public CppStyleHandler() {
33 | registerEnablement();
34 | }
35 |
36 | protected ICEditor getSaveableEditor(ExecutionEvent event) {
37 |
38 | IWorkbenchPart activePart = HandlerUtil.getActivePart(event);
39 |
40 | if (activePart instanceof ICEditor) {
41 | return (ICEditor) activePart;
42 | }
43 |
44 | return null;
45 | }
46 |
47 | /**
48 | * the command has been executed, so extract extract the needed information
49 | * from the application context.
50 | */
51 | @Override
52 | public Object execute(ExecutionEvent event) throws ExecutionException {
53 | ICEditor editor = getSaveableEditor(event);
54 |
55 | if (editor == null) {
56 | return null;
57 | }
58 |
59 | if (!editor.isDirty()) {
60 | return null;
61 | }
62 |
63 | IFile file = ((IFileEditorInput) editor.getEditorInput()).getFile();
64 |
65 | ClangFormatFormatter formater = new ClangFormatFormatter();
66 |
67 | if (formater.runClangFormatOnSave(file)) {
68 | formater.formatAndApply(editor);
69 | }
70 |
71 | IWorkbenchPage page = editor.getSite().getPage();
72 | page.saveEditor(editor, false);
73 |
74 | return null;
75 | }
76 |
77 | @Override
78 | protected EvaluationResult evaluate(IEvaluationContext context) {
79 |
80 | IWorkbenchWindow window = InternalHandlerUtil.getActiveWorkbenchWindow(context);
81 | // no window? not active
82 | if (window == null)
83 | return EvaluationResult.FALSE;
84 | WorkbenchPage page = (WorkbenchPage) window.getActivePage();
85 |
86 | // no page? not active
87 | if (page == null)
88 | return EvaluationResult.FALSE;
89 |
90 | // get saveable part
91 | ISaveablePart saveablePart = getSaveablePart(context);
92 | if (saveablePart == null)
93 | return EvaluationResult.FALSE;
94 |
95 | if (saveablePart instanceof ISaveablesSource) {
96 | ISaveablesSource modelSource = (ISaveablesSource) saveablePart;
97 | if (SaveableHelper.needsSave(modelSource))
98 | return EvaluationResult.TRUE;
99 | return EvaluationResult.FALSE;
100 | }
101 |
102 | if (saveablePart != null && saveablePart.isDirty())
103 | return EvaluationResult.TRUE;
104 |
105 | return EvaluationResult.FALSE;
106 | }
107 | }
108 |
--------------------------------------------------------------------------------
/plugin/src/org/wangzw/plugin/cppstyle/ui/CppStyleMessageConsole.java:
--------------------------------------------------------------------------------
1 | package org.wangzw.plugin.cppstyle.ui;
2 |
3 | import org.eclipse.debug.ui.console.FileLink;
4 | import org.eclipse.jface.text.BadLocationException;
5 | import org.eclipse.jface.text.BadPositionCategoryException;
6 | import org.eclipse.jface.text.IDocument;
7 | import org.eclipse.jface.text.Position;
8 | import org.eclipse.swt.graphics.Color;
9 | import org.eclipse.swt.graphics.RGB;
10 | import org.eclipse.swt.widgets.Display;
11 | import org.eclipse.ui.console.ConsolePlugin;
12 | import org.eclipse.ui.console.IConsoleManager;
13 | import org.eclipse.ui.console.IConsoleView;
14 | import org.eclipse.ui.console.MessageConsole;
15 | import org.eclipse.ui.console.MessageConsoleStream;
16 | import org.eclipse.ui.part.IPageBookViewPage;
17 | import org.wangzw.plugin.cppstyle.CppStyle;
18 |
19 | public class CppStyleMessageConsole extends MessageConsole {
20 | private CppStyleConsolePage page = null;
21 | private MessageConsoleStream out = new MessageConsoleStream(this);
22 | private MessageConsoleStream err = new MessageConsoleStream(this);
23 |
24 | private static class MarkerPosition extends Position {
25 | private FileLink link = null;
26 |
27 | public MarkerPosition(FileLink link, int offset, int length) {
28 | super(offset, length);
29 | this.link = link;
30 | }
31 |
32 | public FileLink getFileLink() {
33 | return link;
34 | }
35 | }
36 |
37 | public static final String ERROR_MARKER_CATEGORY = "org.wangzw.cppstyle.ERROR_MARKER_POSITION";;
38 | private CppStyleConsolePatternMatchListener listener = null;
39 |
40 | public CppStyleMessageConsole(CppStyleConsolePatternMatchListener listener) {
41 | super(CppStyleConstants.CONSOLE_NAME, null);
42 | this.getDocument().addPositionCategory(ERROR_MARKER_CATEGORY);
43 | this.listener = listener;
44 | addPatternMatchListener(listener);
45 |
46 | runUI(new Runnable() {
47 |
48 | @Override
49 | public void run() {
50 | err.setColor(new Color(getStandardDisplay(), new RGB(255, 0, 0)));
51 | };
52 | });
53 | }
54 |
55 | @Override
56 | public IPageBookViewPage createPage(IConsoleView view) {
57 | page = new CppStyleConsolePage(this, view);
58 | return page;
59 | }
60 |
61 | public CppStyleConsolePatternMatchListener getListener() {
62 | return listener;
63 | }
64 |
65 | public void setListener(CppStyleConsolePatternMatchListener listener) {
66 | removePatternMatchListener(this.listener);
67 | addPatternMatchListener(listener);
68 | this.listener = listener;
69 | }
70 |
71 | public CppStyleConsolePage getActivePage() {
72 | return page;
73 | }
74 |
75 | public FileLink getFileLink(int offset) {
76 | try {
77 | IDocument document = getDocument();
78 | if (document != null) {
79 | Position[] positions = document.getPositions(ERROR_MARKER_CATEGORY);
80 | Position position = findPosition(offset, positions);
81 | if (position instanceof MarkerPosition) {
82 | return ((MarkerPosition) position).getFileLink();
83 | }
84 | }
85 | } catch (BadPositionCategoryException e) {
86 | }
87 | return null;
88 | }
89 |
90 | public void addFileLink(FileLink link, int offset, int length) {
91 | IDocument document = getDocument();
92 | MarkerPosition linkPosition = new MarkerPosition(link, offset, length);
93 | try {
94 | document.addPosition(ERROR_MARKER_CATEGORY, linkPosition);
95 | IConsoleManager fConsoleManager = ConsolePlugin.getDefault().getConsoleManager();
96 | fConsoleManager.refresh(this);
97 | } catch (BadPositionCategoryException e) {
98 | CppStyle.log(e);
99 | } catch (BadLocationException e) {
100 | CppStyle.log(e);
101 | }
102 | }
103 |
104 | /**
105 | * Binary search for the position at a given offset.
106 | *
107 | * @param offset
108 | * the offset whose position should be found
109 | * @return the position containing the offset, or null
110 | */
111 | private Position findPosition(int offset, Position[] positions) {
112 |
113 | if (positions.length == 0) {
114 | return null;
115 | }
116 |
117 | int left = 0;
118 | int right = positions.length - 1;
119 | int mid = 0;
120 | Position position = null;
121 |
122 | while (left < right) {
123 |
124 | mid = (left + right) / 2;
125 |
126 | position = positions[mid];
127 | if (offset < position.getOffset()) {
128 | if (left == mid) {
129 | right = left;
130 | } else {
131 | right = mid - 1;
132 | }
133 | } else if (offset > (position.getOffset() + position.getLength() - 1)) {
134 | if (right == mid) {
135 | left = right;
136 | } else {
137 | left = mid + 1;
138 | }
139 | } else {
140 | left = right = mid;
141 | }
142 | }
143 |
144 | position = positions[left];
145 | if (offset >= position.getOffset() && (offset < (position.getOffset() + position.getLength()))) {
146 | return position;
147 | }
148 | return null;
149 | }
150 |
151 | public MessageConsoleStream getOutputStream() {
152 | out.setActivateOnWrite(page != null ? page.activeOnStdout() : true);
153 | return out;
154 | }
155 |
156 | public MessageConsoleStream getErrorStream() {
157 | err.setActivateOnWrite(page != null ? page.activeOnStderr() : true);
158 | return err;
159 | }
160 |
161 | public static Display getStandardDisplay() {
162 | Display display = Display.getCurrent();
163 | if (display == null) {
164 | display = Display.getDefault();
165 | }
166 | return display;
167 | }
168 |
169 | private void runUI(Runnable run) {
170 | Display display;
171 | display = Display.getCurrent();
172 | if (display == null) {
173 | display = Display.getDefault();
174 | display.syncExec(run);
175 | } else {
176 | run.run();
177 | }
178 | }
179 |
180 | public void clear() {
181 | runUI(new Runnable() {
182 |
183 | @Override
184 | public void run() {
185 | IDocument document = getDocument();
186 | document.set("");
187 | };
188 | });
189 |
190 | }
191 | }
192 |
--------------------------------------------------------------------------------
/plugin/src/org/wangzw/plugin/cppstyle/ui/CppStylePerfPage.java:
--------------------------------------------------------------------------------
1 | package org.wangzw.plugin.cppstyle.ui;
2 |
3 | import java.io.File;
4 |
5 | import org.eclipse.jface.preference.BooleanFieldEditor;
6 | import org.eclipse.jface.preference.FieldEditor;
7 | import org.eclipse.jface.preference.FieldEditorPreferencePage;
8 | import org.eclipse.jface.preference.FileFieldEditor;
9 | import org.eclipse.jface.util.PropertyChangeEvent;
10 | import org.eclipse.ui.IWorkbench;
11 | import org.eclipse.ui.IWorkbenchPreferencePage;
12 | import org.wangzw.plugin.cppstyle.ClangFormatFormatter;
13 | import org.wangzw.plugin.cppstyle.CppStyle;
14 |
15 | /**
16 | * This class represents a preference page that is contributed to the
17 | * Preferences dialog. By subclassing FieldEditorPreferencePage, we
18 | * can use the field support built into JFace that allows us to create a page
19 | * that is small and knows how to save, restore and apply itself.
20 | *
21 | * This page is used to modify preferences only. They are stored in the
22 | * preference store that belongs to the main plug-in class. That way,
23 | * preferences can be accessed directly via the preference store.
24 | */
25 |
26 | public class CppStylePerfPage extends FieldEditorPreferencePage implements IWorkbenchPreferencePage {
27 | private FileFieldEditor clangFormatPath = null;
28 | private FileFieldEditor cpplintPath = null;
29 | private BooleanFieldEditor enableCpplintOnSave = null;
30 | private BooleanFieldEditor enableClangFormatOnSave = null;
31 |
32 | public CppStylePerfPage() {
33 | super(GRID);
34 | setPreferenceStore(CppStyle.getDefault().getPreferenceStore());
35 | }
36 |
37 | /**
38 | * Creates the field editors. Field editors are abstractions of the common
39 | * GUI blocks needed to manipulate various types of preferences. Each field
40 | * editor knows how to save and restore itself.
41 | */
42 | public void createFieldEditors() {
43 | clangFormatPath = new FileFieldEditor(CppStyleConstants.CLANG_FORMAT_PATH, "Clang-format path:",
44 | getFieldEditorParent());
45 |
46 | addField(clangFormatPath);
47 |
48 | cpplintPath = new FileFieldEditor(CppStyleConstants.CPPLINT_PATH, "Cpplint path:", getFieldEditorParent());
49 |
50 | addField(cpplintPath);
51 |
52 | enableCpplintOnSave = new BooleanFieldEditor(CppStyleConstants.ENABLE_CPPLINT_ON_SAVE,
53 | CppStyleConstants.ENABLE_CPPLINT_TEXT, getFieldEditorParent());
54 |
55 | if (!checkPathExist(CppStyle.getCpplintPath())) {
56 | enableCpplintOnSave.setEnabled(false, getFieldEditorParent());
57 | }
58 |
59 | addField(enableCpplintOnSave);
60 |
61 | enableClangFormatOnSave = new BooleanFieldEditor(CppStyleConstants.ENABLE_CLANGFORMAT_ON_SAVE,
62 | CppStyleConstants.ENABLE_CLANGFORMAT_TEXT, getFieldEditorParent());
63 |
64 | if (!checkPathExist(ClangFormatFormatter.getClangFormatPath())) {
65 | enableClangFormatOnSave.setEnabled(false, getFieldEditorParent());
66 | }
67 |
68 | addField(enableClangFormatOnSave);
69 | }
70 |
71 | public void init(IWorkbench workbench) {
72 | }
73 |
74 | @Override
75 | public void propertyChange(PropertyChangeEvent event) {
76 | super.propertyChange(event);
77 |
78 | if (event.getProperty().equals(FieldEditor.VALUE)) {
79 | if (event.getSource() == clangFormatPath) {
80 | clangFormatPathChange(event.getNewValue().toString());
81 | } else if (event.getSource() == cpplintPath) {
82 | cpplintPathChange(event.getNewValue().toString());
83 | }
84 |
85 | checkState();
86 | }
87 | }
88 |
89 | private boolean checkPathExist(String path) {
90 | File file = new File(path);
91 | return file.exists() && !file.isDirectory();
92 | }
93 |
94 | private void clangFormatPathChange(String newPath) {
95 | if (!checkPathExist(newPath)) {
96 | enableClangFormatOnSave.setEnabled(false, getFieldEditorParent());
97 | this.setValid(false);
98 | this.setErrorMessage("Clang-format path \"" + newPath + "\" does not exist");
99 | } else {
100 | enableClangFormatOnSave.setEnabled(true, getFieldEditorParent());
101 | this.setValid(true);
102 | this.setErrorMessage(null);
103 | }
104 | }
105 |
106 | private void cpplintPathChange(String newPath) {
107 | if (!checkPathExist(newPath)) {
108 | enableCpplintOnSave.setEnabled(false, getFieldEditorParent());
109 | this.setValid(false);
110 | this.setErrorMessage("Cpplint path \"" + newPath + "\" does not exist");
111 | } else {
112 | enableCpplintOnSave.setEnabled(true, getFieldEditorParent());
113 | this.setValid(true);
114 | this.setErrorMessage(null);
115 | }
116 | }
117 | }
--------------------------------------------------------------------------------
/plugin/src/org/wangzw/plugin/cppstyle/ui/CppStylePropertyPage.java:
--------------------------------------------------------------------------------
1 | package org.wangzw.plugin.cppstyle.ui;
2 |
3 | import java.io.File;
4 |
5 | import org.eclipse.core.resources.IProject;
6 | import org.eclipse.core.resources.IResource;
7 | import org.eclipse.core.runtime.CoreException;
8 | import org.eclipse.core.runtime.QualifiedName;
9 | import org.eclipse.jface.preference.DirectoryFieldEditor;
10 | import org.eclipse.jface.preference.FieldEditor;
11 | import org.eclipse.jface.preference.IPreferenceNode;
12 | import org.eclipse.jface.preference.IPreferencePage;
13 | import org.eclipse.jface.preference.PreferenceDialog;
14 | import org.eclipse.jface.preference.PreferenceManager;
15 | import org.eclipse.jface.preference.PreferenceNode;
16 | import org.eclipse.jface.preference.PreferencePage;
17 | import org.eclipse.jface.util.IPropertyChangeListener;
18 | import org.eclipse.jface.util.PropertyChangeEvent;
19 | import org.eclipse.jface.viewers.ISelection;
20 | import org.eclipse.jface.viewers.IStructuredSelection;
21 | import org.eclipse.swt.SWT;
22 | import org.eclipse.swt.custom.BusyIndicator;
23 | import org.eclipse.swt.events.ModifyEvent;
24 | import org.eclipse.swt.events.ModifyListener;
25 | import org.eclipse.swt.events.SelectionAdapter;
26 | import org.eclipse.swt.events.SelectionEvent;
27 | import org.eclipse.swt.events.SelectionListener;
28 | import org.eclipse.swt.layout.GridData;
29 | import org.eclipse.swt.layout.GridLayout;
30 | import org.eclipse.swt.widgets.Button;
31 | import org.eclipse.swt.widgets.Composite;
32 | import org.eclipse.swt.widgets.Control;
33 | import org.eclipse.swt.widgets.Label;
34 | import org.eclipse.swt.widgets.Text;
35 | import org.eclipse.ui.ISelectionService;
36 | import org.eclipse.ui.dialogs.PropertyPage;
37 | import org.eclipse.ui.internal.Workbench;
38 | import org.wangzw.plugin.cppstyle.CpplintCheckSettings;
39 |
40 | import org.eclipse.cdt.core.model.ICElement;
41 |
42 | public class CppStylePropertyPage extends PropertyPage implements
43 | SelectionListener, IPropertyChangeListener, ModifyListener {
44 |
45 | private static final String PROJECTS_PECIFIC_TEXT = "Enable project specific settings";
46 |
47 | private Button projectSpecificButton;
48 | private Button enableCpplintOnSaveButton;
49 | private Button enableClangFormatOnSaveButton;
50 | private DirectoryFieldEditor projectRoot;
51 | private Text projectRootText = null;
52 | String projectPath = null;
53 |
54 | /**
55 | * Constructor for SamplePropertyPage.
56 | */
57 | public CppStylePropertyPage() {
58 | super();
59 | }
60 |
61 | private void constructPage(Composite parent) {
62 | Composite composite = createComposite(parent, 2);
63 |
64 | projectSpecificButton = new Button(composite, SWT.CHECK);
65 | projectSpecificButton.setText(PROJECTS_PECIFIC_TEXT);
66 | projectSpecificButton.addSelectionListener(this);
67 |
68 | Button perfSetting = new Button(composite, SWT.PUSH);
69 | perfSetting.setText("Configure Workspace Settings...");
70 | perfSetting.addSelectionListener(new SelectionAdapter() {
71 | public void widgetSelected(SelectionEvent e) {
72 | configureWorkspaceSettings();
73 | }
74 | });
75 |
76 | createSepeerater(parent);
77 |
78 | composite = createComposite(parent, 1);
79 |
80 | enableCpplintOnSaveButton = new Button(composite, SWT.CHECK);
81 | enableCpplintOnSaveButton
82 | .setText(CppStyleConstants.ENABLE_CPPLINT_TEXT);
83 | enableCpplintOnSaveButton.addSelectionListener(this);
84 |
85 | enableClangFormatOnSaveButton = new Button(composite, SWT.CHECK);
86 | enableClangFormatOnSaveButton
87 | .setText(CppStyleConstants.ENABLE_CLANGFORMAT_TEXT);
88 | enableClangFormatOnSaveButton.addSelectionListener(this);
89 |
90 | createSepeerater(parent);
91 |
92 | composite = createComposite(parent, 1);
93 |
94 | Label laber = new Label(composite, SWT.NONE);
95 | laber.setText(CppStyleConstants.PROJECT_ROOT_TEXT);
96 |
97 | composite = createComposite(composite, 1);
98 |
99 | projectPath = getCurrentProject();
100 |
101 | projectRoot = new DirectoryFieldEditor(CppStyleConstants.CPPLINT_PATH,
102 | "Root:", composite) {
103 | String errorMsg = super.getErrorMessage();
104 |
105 | @Override
106 | protected boolean doCheckState() {
107 | this.setErrorMessage(errorMsg);
108 |
109 | String fileName = getTextControl().getText();
110 | fileName = fileName.trim();
111 | if (fileName.length() == 0 && isEmptyStringAllowed()) {
112 | return true;
113 | }
114 |
115 | File file = new File(fileName);
116 | if (false == file.isDirectory()) {
117 | return false;
118 | }
119 |
120 | this.setErrorMessage("Directory or its up level directories should contain .git, .hg, or .svn.");
121 |
122 | String path = CpplintCheckSettings.getVersionControlRoot(file);
123 |
124 | if (path == null) {
125 | return false;
126 | }
127 |
128 | if (!path.startsWith(projectPath)) {
129 | this.setErrorMessage("Should be a subdirectory of project's root.");
130 | return false;
131 | }
132 |
133 | return true;
134 | }
135 |
136 | };
137 |
138 | projectRoot.setPage(this);
139 | projectRoot.setFilterPath(new File(projectPath));
140 | projectRoot.setPropertyChangeListener(this);
141 | projectRootText = projectRoot.getTextControl(composite);
142 | projectRootText.addModifyListener(this);
143 | projectRoot.setEnabled(true, composite);
144 |
145 | if (!getPropertyValue(CppStyleConstants.PROJECTS_PECIFIC_PROPERTY)) {
146 | projectSpecificButton.setSelection(false);
147 | enableCpplintOnSaveButton.setEnabled(false);
148 | enableClangFormatOnSaveButton.setEnabled(false);
149 | } else {
150 | projectSpecificButton.setSelection(true);
151 | enableCpplintOnSaveButton.setEnabled(true);
152 | enableCpplintOnSaveButton
153 | .setSelection(getPropertyValue(CppStyleConstants.ENABLE_CPPLINT_PROPERTY));
154 | enableClangFormatOnSaveButton.setEnabled(true);
155 | enableClangFormatOnSaveButton
156 | .setSelection(getPropertyValue(CppStyleConstants.ENABLE_CLANGFORMAT_PROPERTY));
157 | }
158 |
159 | String root = getPropertyValueString(CppStyleConstants.CPPLINT_PROJECT_ROOT);
160 | projectRoot.setStringValue(root);
161 | }
162 |
163 | public static String getCurrentProject() {
164 | ISelectionService selectionService = Workbench.getInstance()
165 | .getActiveWorkbenchWindow().getSelectionService();
166 |
167 | ISelection selection = selectionService.getSelection();
168 |
169 | if (selection instanceof IStructuredSelection) {
170 | Object element = ((IStructuredSelection) selection).getFirstElement();
171 | IProject project = null;
172 | if (element instanceof IResource) {
173 | project = ((IResource) element).getProject();
174 | }
175 | else if (element instanceof ICElement) {
176 | project = ((ICElement) element).getResource().getProject();
177 | }
178 | if (project != null) {
179 | return project.getLocation().toOSString();
180 | }
181 | }
182 | return null;
183 | }
184 |
185 | /**
186 | * @see PreferencePage#createContents(Composite)
187 | */
188 | protected Control createContents(Composite parent) {
189 | Composite composite = new Composite(parent, SWT.NONE);
190 | GridLayout layout = new GridLayout();
191 | composite.setLayout(layout);
192 | GridData data = new GridData(SWT.FILL);
193 | data.grabExcessHorizontalSpace = true;
194 | composite.setLayoutData(data);
195 | constructPage(composite);
196 | return composite;
197 | }
198 |
199 | private Composite createComposite(Composite parent, int ncols) {
200 | Composite composite = new Composite(parent, SWT.NULL);
201 | GridLayout layout = new GridLayout();
202 | layout.numColumns = ncols;
203 | composite.setLayout(layout);
204 |
205 | GridData data = new GridData(SWT.FILL);
206 | data.verticalAlignment = SWT.FILL;
207 | data.horizontalAlignment = SWT.FILL;
208 | data.grabExcessHorizontalSpace = true;
209 | composite.setLayoutData(data);
210 |
211 | return composite;
212 | }
213 |
214 | private void createSepeerater(Composite parent) {
215 | Label separator = new Label(parent, SWT.SEPARATOR | SWT.HORIZONTAL);
216 | GridData gridData = new GridData();
217 | gridData.horizontalAlignment = SWT.FILL;
218 | gridData.grabExcessHorizontalSpace = true;
219 | separator.setLayoutData(gridData);
220 | }
221 |
222 | protected void performDefaults() {
223 | super.performDefaults();
224 | projectSpecificButton.setSelection(false);
225 | enableCpplintOnSaveButton.setSelection(false);
226 | enableCpplintOnSaveButton.setEnabled(false);
227 | enableClangFormatOnSaveButton.setSelection(false);
228 | enableClangFormatOnSaveButton.setEnabled(false);
229 | projectRoot.setStringValue("");
230 | }
231 |
232 | public boolean performOk() {
233 | try {
234 | ((IResource) getElement()).setPersistentProperty(new QualifiedName(
235 | "", CppStyleConstants.PROJECTS_PECIFIC_PROPERTY),
236 | new Boolean(projectSpecificButton.getSelection())
237 | .toString());
238 |
239 | ((IResource) getElement()).setPersistentProperty(new QualifiedName(
240 | "", CppStyleConstants.ENABLE_CPPLINT_PROPERTY),
241 | new Boolean(enableCpplintOnSaveButton.getSelection())
242 | .toString());
243 |
244 | ((IResource) getElement()).setPersistentProperty(new QualifiedName(
245 | "", CppStyleConstants.ENABLE_CLANGFORMAT_PROPERTY),
246 | new Boolean(enableClangFormatOnSaveButton.getSelection())
247 | .toString());
248 |
249 | ((IResource) getElement()).setPersistentProperty(new QualifiedName(
250 | "", CppStyleConstants.CPPLINT_PROJECT_ROOT), projectRoot
251 | .getStringValue());
252 | } catch (CoreException e) {
253 | return false;
254 | }
255 | return true;
256 | }
257 |
258 | public String getPropertyValueString(String key) {
259 | String value;
260 | try {
261 | value = ((IResource) getElement())
262 | .getPersistentProperty(new QualifiedName("", key));
263 | if (value == null) {
264 | return "";
265 | }
266 |
267 | } catch (CoreException e) {
268 | return "";
269 | }
270 |
271 | return value;
272 | }
273 |
274 | public boolean getPropertyValue(String key) {
275 | return Boolean.parseBoolean(getPropertyValueString(key));
276 | }
277 |
278 | /**
279 | * Creates a new preferences page and opens it
280 | */
281 | public void configureWorkspaceSettings() {
282 | // create a new instance of the current class
283 | IPreferencePage page = new CppStylePerfPage();
284 | page.setTitle(getTitle());
285 | // and show it
286 | showPreferencePage(CppStyleConstants.PerfPageId, page);
287 | }
288 |
289 | /**
290 | * Show a single preference pages
291 | *
292 | * @param id
293 | * - the preference page identification
294 | * @param page
295 | * - the preference page
296 | */
297 | protected void showPreferencePage(String id, IPreferencePage page) {
298 | final IPreferenceNode targetNode = new PreferenceNode(id, page);
299 | PreferenceManager manager = new PreferenceManager();
300 | manager.addToRoot(targetNode);
301 | final PreferenceDialog dialog = new PreferenceDialog(getControl()
302 | .getShell(), manager);
303 | BusyIndicator.showWhile(getControl().getDisplay(), new Runnable() {
304 | public void run() {
305 | dialog.create();
306 | dialog.setMessage(targetNode.getLabelText());
307 | dialog.open();
308 | }
309 | });
310 | }
311 |
312 | @Override
313 | public void widgetSelected(SelectionEvent e) {
314 | if (e.getSource() == projectSpecificButton) {
315 | enableCpplintOnSaveButton.setEnabled(projectSpecificButton
316 | .getSelection());
317 | enableClangFormatOnSaveButton.setEnabled(projectSpecificButton
318 | .getSelection());
319 | }
320 | }
321 |
322 | @Override
323 | public void widgetDefaultSelected(SelectionEvent e) {
324 | widgetSelected(e);
325 | }
326 |
327 | @Override
328 | public void propertyChange(PropertyChangeEvent event) {
329 | if (event.getProperty().equals(FieldEditor.VALUE)) {
330 | if (event.getSource() == projectRoot) {
331 | setValid(projectRoot.isValid());
332 | }
333 | }
334 | }
335 |
336 | @Override
337 | public void modifyText(ModifyEvent e) {
338 | if (e.getSource() == projectRootText) {
339 | if (projectRootText.getText().isEmpty()) {
340 | setValid(true);
341 | }
342 | }
343 | }
344 | }
345 |
--------------------------------------------------------------------------------
/plugin/src/org/wangzw/plugin/cppstyle/ui/PreferenceInitializer.java:
--------------------------------------------------------------------------------
1 | package org.wangzw.plugin.cppstyle.ui;
2 |
3 | import java.io.BufferedReader;
4 | import java.io.IOException;
5 | import java.io.InputStreamReader;
6 |
7 | import org.eclipse.core.runtime.preferences.AbstractPreferenceInitializer;
8 | import org.eclipse.jface.preference.IPreferenceStore;
9 | import org.wangzw.plugin.cppstyle.CppStyle;
10 |
11 | /**
12 | * Class used to initialize default preference values.
13 | */
14 | public class PreferenceInitializer extends AbstractPreferenceInitializer {
15 |
16 | public void initializeDefaultPreferences() {
17 | IPreferenceStore store = CppStyle.getDefault().getPreferenceStore();
18 | store.setDefault(CppStyleConstants.CLANG_FORMAT_PATH,
19 | findBinaryPath("clang-format"));
20 | store.setDefault(CppStyleConstants.CPPLINT_PATH,
21 | findBinaryPath("cpplint.py"));
22 | store.setDefault(CppStyleConstants.ENABLE_CPPLINT_ON_SAVE, false);
23 | store.setDefault(CppStyleConstants.ENABLE_CLANGFORMAT_ON_SAVE, false);
24 | }
25 |
26 | private String findBinaryPath(String bin) {
27 | try {
28 | Process process = Runtime.getRuntime().exec("which " + bin);
29 |
30 | if (process.waitFor() == 0) {
31 | BufferedReader reader = new BufferedReader(
32 | new InputStreamReader(process.getInputStream()));
33 | return reader.readLine();
34 | }
35 |
36 | return "";
37 | } catch (IOException e) {
38 | } catch (InterruptedException e) {
39 | }
40 |
41 | return "";
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |