├── .github
└── ISSUE_TEMPLATE.md
├── .gitignore
├── README.md
├── intellij-common
├── .gitignore
└── src
│ └── main
│ └── java
│ └── com
│ └── wix
│ ├── ActualFile.java
│ ├── ThreadLocalActualFile.java
│ ├── annotator
│ ├── AnnotatorUtils.java
│ ├── BaseLintInspection.java
│ ├── ExternalLintAnnotationInput.java
│ ├── ExternalLintAnnotationResult.java
│ └── LintExternalAnnotator.java
│ ├── files
│ ├── ActualFileManager.java
│ ├── BaseActualFile.java
│ ├── OriginalFile.java
│ ├── RelativeFile.java
│ └── TempFile.java
│ ├── nodejs
│ ├── CLI.java
│ ├── NodeFinder.java
│ └── NodeRunner.java
│ ├── settings
│ ├── ValidationInfo.java
│ ├── ValidationUtils.java
│ └── Validator.java
│ └── utils
│ ├── FileUtils.java
│ ├── PsiUtil.java
│ └── Strings.java
└── scss-lint-plugin
├── .gitignore
├── LICENSE
├── build.gradle
├── docs
├── Inspection.png
├── PropertySortRule.png
├── Rule.png
└── Settings.png
├── gradlew
├── gradlew.bat
├── lib
└── xstream-1.4.7.jar
├── settings.gradle
└── src
├── log4j-old.properties
├── log4j.xml
├── log4j0.xml
├── main
├── java
│ └── com
│ │ └── scss
│ │ ├── EditSettingsAction.java
│ │ ├── ScssLintBundle.java
│ │ ├── ScssLintExternalAnnotator.java
│ │ ├── ScssLintInspection.java
│ │ ├── ScssLintProjectComponent.java
│ │ ├── ThreadLocalActualFile.java
│ │ ├── annotator
│ │ ├── BaseActionFix.java
│ │ ├── Fixes.java
│ │ ├── PropertySortOrderFix.java
│ │ └── SortProperty.kt
│ │ ├── config
│ │ ├── ScssLintConfigFileChangeTracker.java
│ │ ├── ScssLintConfigFileType.java
│ │ ├── ScssLintConfigFileTypeFactory.java
│ │ └── ScssLintConfigFileUtil.java
│ │ ├── settings
│ │ ├── ScssLintSettingsPage.form
│ │ ├── ScssLintSettingsPage.java
│ │ └── Settings.java
│ │ └── utils
│ │ ├── ScssLintFinder.java
│ │ ├── ScssLintRunner.java
│ │ └── scssLint
│ │ ├── Lint.java
│ │ ├── LintResult.java
│ │ └── Outdated.java
└── resources
│ ├── META-INF
│ └── plugin.xml
│ ├── com
│ └── scss
│ │ └── ScssLintBundle.properties
│ └── inspectionDescriptions
│ └── ScssLintInspection.html
└── test
├── java
├── com
│ └── scsslint
│ │ ├── ScssLintTest.java
│ │ ├── TestUtils.java
│ │ ├── TestUtils2.java
│ │ └── utils
│ │ ├── ConfigFinderTest.java
│ │ ├── PrintAppDataDir.java
│ │ ├── ScssLintRunner2Test.java
│ │ ├── ScssLintRunnerTest.java
│ │ └── Settings.java
└── log4j.properties
└── resources
├── .scss-lint.yml
├── inspections
├── CapitalizationInSelector.scss
├── EmptyRule.scss
├── HexLength.scss
└── one.scss
├── one.scss
└── one.xml
/.github/ISSUE_TEMPLATE.md:
--------------------------------------------------------------------------------
1 |
2 | ### Versions
3 |
4 | scss-lint version: [?]
5 | You can get this information from executing `scss-lint --version` at the command line.
6 |
7 | OS: [?]
8 | IDEA product and version: [e.g. webstorm 11]
9 |
10 | ### Description
11 |
12 | [Description of the bug or feature]
13 |
14 | ### Steps to Reproduce
15 |
16 | 1. [First Step]
17 | 2. [Second Step]
18 | 3. [and so on...]
19 |
20 | **Expected behavior:** [What you expected to happen]
21 |
22 | **Actual behavior:** [What actually happened]
23 |
24 |
25 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | ### OSX ###
2 | .DS_Store
3 | .AppleDouble
4 | .LSOverride
5 |
6 | # Icon must ends with two \r.
7 | Icon
8 |
9 |
10 | # Thumbnails
11 | ._*
12 |
13 | # Files that might appear on external disk
14 | .Spotlight-V100
15 | .Trashes
16 |
17 | .idea
18 | out
19 |
20 | /scss-lint-test
21 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # SCSS Lint Plugin #
2 |
3 | [scss-lint](https://github.com/causes/scss-lint) is a tool to help keep your SCSS files clean and readable. see more [here](https://github.com/causes/scss-lint).
4 | SCSS Lint plugin for WebStorm, PHPStorm and other Idea family IDE with Javascript plugin, provides integration with SCSS Lint and shows errors and warnings inside the editor.
5 | * Support displaying SCSS Lint warnings as intellij inspections
6 | * Support quick fix for PropertySortRule that sorts the properties
7 |
8 | ## Getting started ##
9 | ### Prerequisites ###
10 | Install scss-lint on your machine see instructions [here](https://github.com/causes/scss-lint#installation):
11 |
12 | ### Settings ###
13 | To get started, you need to set the SCSS Lint plugin settings:
14 |
15 | * Go to preferences, SCSS Lint plugin page and check the Enable plugin.
16 | * Select the path to the SCSS Lint executable. (for windows users this might be your [rubypath]\bin\scss-lint.bat)
17 | * You can use the command `gem environment` to figure out where your gems are installed. Look for `GEM PATHS`.
18 | * Set the .scss-lint.yml file, or scss-lint will use the default settings.
19 | * By default, SCSS Lint plugin annotate the editor with warning or error based on the SCSS Lint configuration, you can check the 'Treat all SCSS Lint issues as warnings' checkbox to display all issues from SCSS Lint as warnings.
20 |
21 |
22 | Configuration:
23 | 
24 |
25 |
26 | Inspection:
27 | 
28 |
29 |
30 | Analyze Code:
31 | 
32 |
--------------------------------------------------------------------------------
/intellij-common/.gitignore:
--------------------------------------------------------------------------------
1 | # /**/*.iml
2 | /target
3 | /.idea
4 |
5 | # Created by http://www.gitignore.io
6 |
7 | ### Intellij ###
8 | # Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm
9 |
10 | ## Directory-based project format
11 | .idea/
12 | # if you remove the above rule, at least ignore user-specific stuff:
13 | # .idea/workspace.xml
14 | # .idea/tasks.xml
15 | # and these sensitive or high-churn files:
16 | # .idea/dataSources.ids
17 | # .idea/dataSources.xml
18 | # .idea/sqlDataSources.xml
19 | # .idea/dynamic.xml
20 |
21 | ## File-based project format
22 | *.ipr
23 | *.iws
24 | *.iml
25 |
26 | ## Additional for IntelliJ
27 | out/
28 |
29 | # generated by mpeltonen/sbt-idea plugin
30 | .idea_modules/
31 |
32 | # generated by JIRA plugin
33 | atlassian-ide-plugin.xml
34 |
35 | # generated by Crashlytics plugin (for Android Studio and Intellij)
36 | com_crashlytics_export_strings.xml
37 |
38 |
39 | ### OSX ###
40 | .DS_Store
41 | .AppleDouble
42 | .LSOverride
43 |
44 | # Icon must ends with two \r.
45 | Icon
46 |
47 |
48 | # Thumbnails
49 | ._*
50 |
51 | # Files that might appear on external disk
52 | .Spotlight-V100
53 | .Trashes
54 |
55 | node_modules
56 | coverage
57 | target
58 | build
59 | npm-debug.log
60 |
61 | temp
62 |
63 | # gradle
64 | .gradle
65 | /build
66 | gradle.properties
67 |
--------------------------------------------------------------------------------
/intellij-common/src/main/java/com/wix/ActualFile.java:
--------------------------------------------------------------------------------
1 | package com.wix;
2 |
3 | import com.intellij.openapi.diagnostic.Logger;
4 | import com.intellij.openapi.editor.Document;
5 | import com.intellij.openapi.fileEditor.FileDocumentManager;
6 | import com.intellij.openapi.util.Key;
7 | import com.intellij.openapi.util.io.FileUtil;
8 | import com.intellij.openapi.vfs.VirtualFile;
9 | import org.jetbrains.annotations.NotNull;
10 | import org.jetbrains.annotations.Nullable;
11 |
12 | import java.io.File;
13 | import java.io.IOException;
14 |
15 | /**
16 | * Process target file, either the real file or a temp file
17 | */
18 | public class ActualFile {
19 | private static final Logger LOG = Logger.getInstance(Util.LOG_ID);
20 |
21 | ActualFile(File file, File tempFile) {
22 | this.file = file;
23 | this.tempFile = tempFile;
24 | }
25 |
26 | ActualFile(File file) {
27 | this(file, null);
28 | }
29 |
30 | private final File file;
31 | private final File tempFile;
32 |
33 | public File getFile() {
34 | return file;
35 | }
36 |
37 | public File getActualFile() {
38 | if (tempFile != null) {
39 | return tempFile;
40 | }
41 | return file;
42 | }
43 |
44 | public void deleteTemp() {
45 | if (tempFile != null && tempFile.exists() && tempFile.isFile()) {
46 | boolean isDeleted = tempFile.delete();
47 | if (!isDeleted) {
48 | LOG.debug("Failed to delete temp file");
49 | }
50 | }
51 | }
52 |
53 | @Nullable
54 | public static ActualFile getOrCreateActualFile(@NotNull Key key, @NotNull VirtualFile virtualFile, @Nullable String content) {
55 | FileDocumentManager fileDocumentManager = FileDocumentManager.getInstance();
56 | if (!fileDocumentManager.isFileModified(virtualFile)) {
57 | File file = new File(virtualFile.getPath());
58 | if (file.isFile()) {
59 | return new ActualFile(file);
60 | }
61 | }
62 | ThreadLocalActualFile threadLocal = key.get(virtualFile);
63 | if (threadLocal == null) {
64 | threadLocal = virtualFile.putUserDataIfAbsent(key, new ThreadLocalActualFile(virtualFile));
65 | }
66 | File file = threadLocal.getOrCreateFile();
67 | if (file == null) {
68 | return null;
69 | }
70 | if (content == null) {
71 | Document document = fileDocumentManager.getDocument(virtualFile);
72 | if (document != null) {
73 | content = document.getText();
74 | }
75 | }
76 | if (content == null) {
77 | return null;
78 | }
79 | try {
80 | FileUtil.writeToFile(file, content);
81 | return new ActualFile(new File(virtualFile.getPath()), file);
82 | } catch (IOException e) {
83 | LOG.warn("Can not write to " + file.getAbsolutePath(), e);
84 | }
85 | return null;
86 | }
87 | }
88 |
--------------------------------------------------------------------------------
/intellij-common/src/main/java/com/wix/ThreadLocalActualFile.java:
--------------------------------------------------------------------------------
1 | package com.wix;
2 |
3 | import com.intellij.openapi.diagnostic.Logger;
4 | import com.intellij.openapi.util.io.FileUtil;
5 | import com.intellij.openapi.vfs.VirtualFile;
6 | import com.wix.utils.FileUtils;
7 | import org.jetbrains.annotations.NotNull;
8 | import org.jetbrains.annotations.Nullable;
9 |
10 | import java.io.File;
11 | import java.io.IOException;
12 |
13 | /**
14 | * Lint target file thread local storage
15 | */
16 | public class ThreadLocalActualFile extends ThreadLocal {
17 | private final String baseName;
18 | private final String extension;
19 | private final VirtualFile originalFile;
20 | private File tempFile;
21 | private static final Logger LOG = Logger.getInstance(Util.LOG_ID);
22 |
23 | public boolean isTemp;
24 |
25 | private static final String SCSS_LINT_TMP = "_scsslint_tmp";
26 | private static final String TEMP_DIR_NAME = "intellij-scsslint-temp";
27 |
28 | public ThreadLocalActualFile(@NotNull VirtualFile originalFile) {
29 | this.baseName = originalFile.getNameWithoutExtension();
30 | this.extension = FileUtils.getExtensionWithDot(originalFile);
31 | this.originalFile = originalFile;
32 | }
33 |
34 | public VirtualFile getFile() {
35 | return originalFile;
36 | }
37 |
38 | @Nullable
39 | public File getOrCreateFile() {
40 | String path = super.get();
41 | if (path != null) {
42 | File file = new File(path);
43 | if (file.isFile()) {
44 | return file;
45 | }
46 | }
47 | File file = createFile();
48 | if (file != null) {
49 | set(file.getAbsolutePath());
50 | tempFile = file;
51 | return file;
52 | }
53 | return null;
54 | }
55 |
56 | @Nullable
57 | public static File getOrCreateTempDir() {
58 | File tmpDir = new File(FileUtil.getTempDirectory());
59 | File dir = new File(tmpDir, TEMP_DIR_NAME);
60 | if (dir.isDirectory() || dir.mkdirs()) {
61 | return dir;
62 | }
63 | try {
64 | return FileUtil.createTempDirectory(tmpDir, TEMP_DIR_NAME, null);
65 | } catch (IOException ignored) {
66 | LOG.warn("Can't create '" + TEMP_DIR_NAME + "' temporary directory.");
67 | }
68 | return null;
69 | }
70 |
71 | private File createFileAsSibling() {
72 | File retFile;
73 | try {
74 | // try to create a temp file next to original file
75 | retFile = File.createTempFile(this.baseName + SCSS_LINT_TMP, this.extension, new File(originalFile.getParent().getPath()));
76 | isTemp = true;
77 | return retFile;
78 | } catch (IOException e) {
79 | LOG.warn("Can not create temp file", e);
80 | }
81 | return null;
82 | }
83 |
84 | @Nullable
85 | private File createFile() {
86 | // File retFile = new File(file.getParent().getPath(), file.getNameWithoutExtension() + "_jscs_tmp." + file.getExtension());
87 | File retFile = createFileAsSibling();
88 | if (retFile != null) {
89 | return retFile;
90 | }
91 |
92 | // try to create a temp file in temp folder
93 | File dir = getOrCreateTempDir();
94 | if (dir == null) {
95 | return null;
96 | }
97 | File file = new File(dir, this.baseName + this.extension);
98 | boolean created = false;
99 | if (!file.exists()) {
100 | try {
101 | created = file.createNewFile();
102 | } catch (IOException ignored) {
103 | LOG.warn("Can not create " + file.getAbsolutePath());
104 | }
105 | }
106 | if (!created) {
107 | try {
108 | file = FileUtil.createTempFile(dir, this.baseName, this.extension);
109 | } catch (IOException e) {
110 | LOG.warn("Can not create temp file", e);
111 | return null;
112 | }
113 | }
114 | file.deleteOnExit();
115 | return file;
116 | }
117 | }
118 |
--------------------------------------------------------------------------------
/intellij-common/src/main/java/com/wix/annotator/AnnotatorUtils.java:
--------------------------------------------------------------------------------
1 | package com.wix.annotator;
2 |
3 | import com.intellij.codeInsight.daemon.impl.HighlightInfoType;
4 | import com.intellij.codeInsight.daemon.impl.SeverityRegistrar;
5 | import com.intellij.lang.annotation.HighlightSeverity;
6 | import com.intellij.openapi.editor.colors.EditorColorsManager;
7 | import com.intellij.openapi.editor.colors.EditorColorsScheme;
8 | import com.intellij.openapi.editor.colors.TextAttributesKey;
9 | import com.intellij.openapi.editor.markup.TextAttributes;
10 | import org.jetbrains.annotations.NotNull;
11 | import org.jetbrains.annotations.Nullable;
12 |
13 | public final class AnnotatorUtils {
14 | private AnnotatorUtils() {
15 | }
16 |
17 | @NotNull
18 | public static TextAttributes getTextAttributes(@Nullable EditorColorsScheme editorColorsScheme, @NotNull SeverityRegistrar severityRegistrar, @NotNull HighlightSeverity severity) {
19 | TextAttributes textAttributes = severityRegistrar.getTextAttributesBySeverity(severity);
20 | if (textAttributes != null) {
21 | return textAttributes;
22 | }
23 | EditorColorsScheme colorsScheme = getColorsScheme(editorColorsScheme);
24 | HighlightInfoType.HighlightInfoTypeImpl infoType = severityRegistrar.getHighlightInfoTypeBySeverity(severity);
25 | TextAttributesKey key = infoType.getAttributesKey();
26 | return colorsScheme.getAttributes(key);
27 | }
28 |
29 | @NotNull
30 | private static EditorColorsScheme getColorsScheme(@Nullable EditorColorsScheme customScheme) {
31 | return customScheme == null ? EditorColorsManager.getInstance().getGlobalScheme() : customScheme;
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/intellij-common/src/main/java/com/wix/annotator/BaseLintInspection.java:
--------------------------------------------------------------------------------
1 | package com.wix.annotator;
2 |
3 | import com.intellij.codeInspection.*;
4 | import com.intellij.codeInspection.ex.UnfairLocalInspectionTool;
5 | import com.intellij.lang.annotation.ExternalAnnotator;
6 | import com.intellij.psi.PsiElementVisitor;
7 | import com.intellij.psi.PsiFile;
8 | import org.jetbrains.annotations.NotNull;
9 |
10 | public abstract class BaseLintInspection extends LocalInspectionTool implements BatchSuppressableTool, UnfairLocalInspectionTool { //extends PropertySuppressableInspectionBase {
11 |
12 | protected abstract ExternalAnnotator getExternalAnnotator();
13 |
14 | public ProblemDescriptor[] checkFile(@NotNull PsiFile file, @NotNull final InspectionManager manager, final boolean isOnTheFly) {
15 | return ExternalAnnotatorInspectionVisitor.checkFileWithExternalAnnotator(file, manager, isOnTheFly, getExternalAnnotator());
16 | }
17 |
18 | @NotNull
19 | @Override
20 | public PsiElementVisitor buildVisitor(@NotNull ProblemsHolder holder, boolean isOnTheFly, @NotNull LocalInspectionToolSession session) {
21 | return new ExternalAnnotatorInspectionVisitor(holder, getExternalAnnotator(), isOnTheFly);
22 | }
23 | }
--------------------------------------------------------------------------------
/intellij-common/src/main/java/com/wix/annotator/ExternalLintAnnotationInput.java:
--------------------------------------------------------------------------------
1 | package com.wix.annotator;
2 |
3 | import com.intellij.openapi.editor.colors.EditorColorsScheme;
4 | import com.intellij.openapi.project.Project;
5 | import com.intellij.psi.PsiFile;
6 |
7 | public class ExternalLintAnnotationInput {
8 | public final String fileContent;
9 | public final EditorColorsScheme colorsScheme;
10 | public final Project project;
11 | public final PsiFile psiFile;
12 |
13 | public ExternalLintAnnotationInput(Project project, PsiFile psiFile, String fileContent, EditorColorsScheme colorsScheme) {
14 | this.project = project;
15 | this.psiFile = psiFile;
16 | this.fileContent = fileContent;
17 | this.colorsScheme = colorsScheme;
18 | }
19 | }
--------------------------------------------------------------------------------
/intellij-common/src/main/java/com/wix/annotator/ExternalLintAnnotationResult.java:
--------------------------------------------------------------------------------
1 | package com.wix.annotator;
2 |
3 | public class ExternalLintAnnotationResult {
4 | public ExternalLintAnnotationResult(ExternalLintAnnotationInput input, T result) {
5 | this.input = input;
6 | this.result = result;
7 | }
8 |
9 | public final ExternalLintAnnotationInput input;
10 | public final T result;
11 | }
--------------------------------------------------------------------------------
/intellij-common/src/main/java/com/wix/annotator/LintExternalAnnotator.java:
--------------------------------------------------------------------------------
1 | package com.wix.annotator;
2 |
3 | import com.intellij.lang.annotation.ExternalAnnotator;
4 | import com.intellij.openapi.editor.Editor;
5 | import com.intellij.psi.PsiFile;
6 | import org.jetbrains.annotations.NotNull;
7 | import org.jetbrains.annotations.Nullable;
8 |
9 | /**
10 | * @author idok
11 | */
12 | public abstract class LintExternalAnnotator extends ExternalAnnotator> {
13 |
14 | @Nullable
15 | @Override
16 | public ExternalLintAnnotationInput collectInformation(@NotNull PsiFile file) {
17 | return collectInformation(file, null);
18 | }
19 |
20 | @Nullable
21 | @Override
22 | public ExternalLintAnnotationInput collectInformation(@NotNull PsiFile file, @NotNull Editor editor, boolean hasErrors) {
23 | return collectInformation(file, editor);
24 | }
25 |
26 | protected abstract ExternalLintAnnotationInput collectInformation(PsiFile file, Editor editor);
27 | }
28 |
--------------------------------------------------------------------------------
/intellij-common/src/main/java/com/wix/files/ActualFileManager.java:
--------------------------------------------------------------------------------
1 | package com.wix.files;
2 |
3 | import com.intellij.openapi.diagnostic.Logger;
4 | import com.intellij.openapi.editor.Document;
5 | import com.intellij.openapi.fileEditor.FileDocumentManager;
6 | import com.intellij.openapi.util.Key;
7 | import com.intellij.openapi.util.io.FileUtil;
8 | import com.intellij.openapi.vfs.VirtualFile;
9 | import com.intellij.psi.PsiFile;
10 | import com.wix.Util;
11 | import org.jetbrains.annotations.NotNull;
12 | import org.jetbrains.annotations.Nullable;
13 |
14 | import java.io.File;
15 | import java.io.IOException;
16 |
17 | public final class ActualFileManager {
18 | private static final Logger LOG = Logger.getInstance(Util.LOG_ID);
19 |
20 | private ActualFileManager() {
21 | }
22 |
23 | @Nullable
24 | public static BaseActualFile getOrCreateActualFile(@NotNull Key key, @NotNull PsiFile psiFile, @Nullable String content) {
25 | // Original file
26 | VirtualFile virtualFile = psiFile.getVirtualFile();
27 | FileDocumentManager fileDocumentManager = FileDocumentManager.getInstance();
28 | if (!fileDocumentManager.isFileModified(virtualFile)) {
29 | File file = new File(virtualFile.getPath());
30 | if (file.isFile()) {
31 | return new OriginalFile(psiFile, file);
32 | }
33 | }
34 |
35 | // TEMP File
36 | ThreadLocalTempActualFile threadLocal = key.get(virtualFile);
37 | if (threadLocal == null) {
38 | threadLocal = virtualFile.putUserDataIfAbsent(key, new ThreadLocalTempActualFile("scss-temp", psiFile));
39 | }
40 | RelativeFile file = threadLocal.getOrCreateFile();
41 | if (file == null) {
42 | return null;
43 | }
44 | if (content == null) {
45 | Document document = fileDocumentManager.getDocument(virtualFile);
46 | if (document != null) {
47 | content = document.getText();
48 | }
49 | }
50 | if (content == null) {
51 | return null;
52 | }
53 | try {
54 | FileUtil.writeToFile(file.file, content);
55 | return new TempFile(psiFile, new File(virtualFile.getPath()), file);
56 | } catch (IOException e) {
57 | LOG.warn("Can not write to " + file.file.getAbsolutePath(), e);
58 | }
59 | return null;
60 | }
61 |
62 | public static void dispose(BaseActualFile actualCodeFile) {
63 | if (actualCodeFile != null) {
64 | actualCodeFile.deleteTemp();
65 | }
66 | }
67 | }
68 |
--------------------------------------------------------------------------------
/intellij-common/src/main/java/com/wix/files/BaseActualFile.java:
--------------------------------------------------------------------------------
1 | package com.wix.files;
2 |
3 | import com.intellij.psi.PsiFile;
4 | import com.wix.utils.FileUtils;
5 | import org.jetbrains.annotations.NotNull;
6 |
7 | import java.io.File;
8 |
9 | /**
10 | * Process target file, either the real file or a temp file
11 | */
12 | public abstract class BaseActualFile {
13 | BaseActualFile(PsiFile psiFile, File file) {
14 | this.file = file;
15 | this.psiFile = psiFile;
16 | }
17 |
18 | protected final File file;
19 | private final PsiFile psiFile;
20 |
21 | public File getActualFile() {
22 | return file;
23 | }
24 |
25 | public void deleteTemp() {
26 | }
27 |
28 | @NotNull
29 | public String getPath() {
30 | return FileUtils.makeRelative(new File(psiFile.getProject().getBasePath()), file);
31 | }
32 |
33 | @NotNull
34 | public String getCwd() {
35 | return psiFile.getProject().getBasePath();
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/intellij-common/src/main/java/com/wix/files/OriginalFile.java:
--------------------------------------------------------------------------------
1 | package com.wix.files;
2 |
3 | import com.intellij.psi.PsiFile;
4 | import org.jetbrains.annotations.NotNull;
5 |
6 | import java.io.File;
7 |
8 | public class OriginalFile extends BaseActualFile {
9 | OriginalFile(@NotNull PsiFile psiFile, File file) {
10 | super(psiFile, file);
11 | }
12 | }
--------------------------------------------------------------------------------
/intellij-common/src/main/java/com/wix/files/RelativeFile.java:
--------------------------------------------------------------------------------
1 | package com.wix.files;
2 |
3 | import java.io.File;
4 |
5 | public class RelativeFile {
6 | public final File root;
7 | public final File file;
8 |
9 | public RelativeFile(File root, File file) {
10 | this.root = root;
11 | this.file = file;
12 | }
13 | }
--------------------------------------------------------------------------------
/intellij-common/src/main/java/com/wix/files/TempFile.java:
--------------------------------------------------------------------------------
1 | package com.wix.files;
2 |
3 | import com.intellij.openapi.diagnostic.Logger;
4 | import com.intellij.psi.PsiFile;
5 | import com.wix.Util;
6 | import org.jetbrains.annotations.NotNull;
7 |
8 | import java.io.File;
9 |
10 | public class TempFile extends BaseActualFile {
11 | private static final Logger LOG = Logger.getInstance(Util.LOG_ID);
12 | private final RelativeFile tempFile;
13 |
14 | TempFile(PsiFile psiFile, File file, RelativeFile tempFile) {
15 | super(psiFile, file);
16 | this.tempFile = tempFile;
17 | }
18 |
19 | @Override
20 | public File getActualFile() {
21 | return tempFile.file;
22 | }
23 |
24 | public RelativeFile getTempFile() {
25 | return tempFile;
26 | }
27 |
28 | @Override
29 | public void deleteTemp() {
30 | File temp = tempFile.file;
31 | if (temp != null && temp.exists() && temp.isFile()) {
32 | boolean isDeleted = temp.delete();
33 | if (!isDeleted) {
34 | LOG.debug("Failed to delete temp file");
35 | }
36 | }
37 | }
38 |
39 | @NotNull
40 | public String getPath() {
41 | return tempFile.file.getAbsolutePath();
42 | }
43 |
44 | @NotNull
45 | @Override
46 | public String getCwd() {
47 | return tempFile.root.getAbsolutePath();
48 | }
49 | }
--------------------------------------------------------------------------------
/intellij-common/src/main/java/com/wix/nodejs/CLI.java:
--------------------------------------------------------------------------------
1 | package com.wix.nodejs;
2 |
3 | import com.intellij.execution.configurations.GeneralCommandLine;
4 | import com.intellij.openapi.util.SystemInfo;
5 | import com.intellij.openapi.util.text.StringUtil;
6 |
7 | public class CLI {
8 | public static final String JSON = "json";
9 | public static final String FORMAT = "-f";
10 | public static final String NO_COLOR = "--no-color";
11 | public static final String VERSION = "--version";
12 | public static final String V = "-v";
13 | public static final String PARAM = "--";
14 | public static final String ALIAS = "-";
15 |
16 | private final GeneralCommandLine commandLine = new GeneralCommandLine();
17 |
18 | public CLI(String cwd, String node, String exe) {
19 | if (SystemInfo.isWindows) {
20 | commandLine.setExePath(exe);
21 | } else {
22 | commandLine.setExePath(node);
23 | commandLine.addParameter(exe);
24 | }
25 | commandLine.setWorkDirectory(cwd);
26 | }
27 |
28 | public CLI noColor() {
29 | return param(NO_COLOR);
30 | }
31 |
32 | public CLI param(String value) {
33 | commandLine.addParameter(value);
34 | return this;
35 | }
36 |
37 | public CLI param(String key, String value) {
38 | commandLine.addParameter(key);
39 | commandLine.addParameter(value);
40 | return this;
41 | }
42 |
43 | public CLI json() {
44 | return param(FORMAT, JSON);
45 | }
46 |
47 | public GeneralCommandLine cmd() {
48 | return commandLine;
49 | }
50 |
51 | public static void addParam(GeneralCommandLine commandLine, String name, String value) {
52 | commandLine.addParameter(name);
53 | commandLine.addParameter(value);
54 | }
55 |
56 | public static void addParamIfNotEmpty(GeneralCommandLine commandLine, String name, String value) {
57 | if (StringUtil.isNotEmpty(value)) {
58 | addParam(commandLine, name, value);
59 | }
60 | }
61 | }
62 |
--------------------------------------------------------------------------------
/intellij-common/src/main/java/com/wix/nodejs/NodeFinder.java:
--------------------------------------------------------------------------------
1 | package com.wix.nodejs;
2 |
3 | import com.google.common.base.Joiner;
4 | import com.intellij.execution.configurations.PathEnvironmentVariableUtil;
5 | import com.intellij.openapi.util.SystemInfo;
6 | import com.intellij.openapi.util.text.StringUtil;
7 | import com.intellij.util.EnvironmentUtil;
8 | import com.intellij.util.containers.ContainerUtil;
9 | import org.jetbrains.annotations.NotNull;
10 | import org.jetbrains.annotations.Nullable;
11 |
12 | import java.io.File;
13 | import java.util.Arrays;
14 | import java.util.Collections;
15 | import java.util.List;
16 | import java.util.Set;
17 | import java.util.regex.Matcher;
18 | import java.util.regex.Pattern;
19 |
20 | public final class NodeFinder {
21 | // public static final String RT_BASE_NAME = SystemInfo.isWindows ? "rt.cmd" : "rt";
22 | private static final Pattern NVM_NODE_DIR_NAME_PATTERN = Pattern.compile("^v?(\\d+)\\.(\\d+)\\.(\\d+)$");
23 | public static final String NODE_MODULES = "node_modules";
24 |
25 | // TODO figure out a way to automatically get this path or add it to config
26 | // should read from /usr/local/lib/node_modules/eslint/lib/rules
27 | // public static String defaultPath = "/usr/local/lib/node_modules/eslint/lib/rules";
28 | // c:/users/user/appdata/roaming/npm/node_modules
29 |
30 | private NodeFinder() {
31 | }
32 |
33 | public static String getBinName(String baseBinName) {
34 | return SystemInfo.isWindows ? baseBinName + ".cmd" : baseBinName;
35 | }
36 |
37 | // List infos = ContainerUtil.newArrayList();
38 | // NodeModuleSearchUtil.findModulesWithName(infos, "eslint", project.getBaseDir(), null, false);
39 |
40 | // @Nullable
41 | // public static File findInterpreterInPath() {
42 | // return PathEnvironmentVariableUtil.findInPath(RT_BASE_NAME);
43 | // }
44 |
45 | @NotNull
46 | public static List searchNodeModulesBin(String exeFileName) {
47 | Set interpreters = ContainerUtil.newLinkedHashSet();
48 | List fromPath = PathEnvironmentVariableUtil.findAllExeFilesInPath(exeFileName);
49 | List nvmInterpreters = listNodeInterpretersFromNvm(exeFileName);
50 | List brewInterpreters = listNodeInterpretersFromHomeBrew(exeFileName);
51 | interpreters.addAll(fromPath);
52 | interpreters.removeAll(nvmInterpreters);
53 | interpreters.removeAll(brewInterpreters);
54 | interpreters.addAll(nvmInterpreters);
55 | interpreters.addAll(brewInterpreters);
56 | return ContainerUtil.newArrayList(interpreters);
57 | }
58 |
59 | @NotNull
60 | public static List searchAllScopesForBin(File projectRoot, String exeFileName) {
61 | // List nodeModules = searchProjectNodeModules(projectRoot);
62 | List globalJscsBin = searchNodeModulesBin(exeFileName);
63 | File file = resolvePath(projectRoot, NODE_MODULES, ".bin", exeFileName);
64 | if (file.exists()) {
65 | globalJscsBin.add(file);
66 | }
67 |
68 | // if (SystemInfo.isWindows) {
69 | // File file = resolvePath(projectRoot, NODE_MODULES, ".bin", exeFileName);
70 | // if (file.exists()) {
71 | // globalJscsBin.add(file);
72 | // }
73 | // } else {
74 | // File file = resolvePath(projectRoot, NODE_MODULES, ".bin", exeFileName);
75 | // if (file.exists()) {
76 | // globalJscsBin.add(file);
77 | // }
78 | // }
79 | // globalJscsBin.addAll(nodeModules);
80 | return globalJscsBin;
81 | }
82 |
83 | // @NotNull
84 | // public static List searchForRTBin(File projectRoot) {
85 | //// List nodeModules = searchProjectNodeModules(projectRoot);
86 | // List globalRTBin = listPossibleRTExe(exeFileName);
87 |
88 | // if (SystemInfo.isWindows) {
89 | // File file = resolvePath(projectRoot, NODE_MODULES, ".bin", "rt.cmd");
90 | // if (file.exists()) {
91 | // globalRTBin.add(file);
92 | // }
93 | // } else {
94 | // File file = resolvePath(projectRoot, NODE_MODULES, "react-templates", "bin", "rt.js");
95 | // if (file.exists()) {
96 | // globalRTBin.add(file);
97 | // }
98 | // }
99 | //// globalRTBin.addAll(nodeModules);
100 | // return globalRTBin;
101 | // }
102 |
103 |
104 | public static File resolvePath(File root, @Nullable String first, @Nullable String second, String... rest) {
105 | String path = buildPath(first, second, rest);
106 | return new File(root, path);
107 | }
108 |
109 | public static String buildPath(@Nullable String first, @Nullable String second, String... rest) {
110 | return Joiner.on(File.separatorChar).join(first, second, (Object[]) rest);
111 | }
112 |
113 | @NotNull
114 | public static List listNodeInterpretersFromNvm(String exeFileName) {
115 | String nvmDirPath = EnvironmentUtil.getValue("NVM_DIR");
116 | if (StringUtil.isEmpty(nvmDirPath)) {
117 | return Collections.emptyList();
118 | }
119 | File nvmDir = new File(nvmDirPath);
120 | if (nvmDir.isDirectory() && nvmDir.isAbsolute()) {
121 | return listNodeInterpretersFromVersionDir(nvmDir, exeFileName);
122 | }
123 | return Collections.emptyList();
124 | }
125 |
126 | public static List listNodeInterpretersFromHomeBrew(String exeFileName) {
127 | return listNodeInterpretersFromVersionDir(new File("/usr/local/Cellar/node"), exeFileName);
128 | }
129 |
130 | public static List listNodeInterpretersFromVersionDir(@NotNull File parentDir, String exeFileName) {
131 | if (!parentDir.isDirectory()) {
132 | return Collections.emptyList();
133 | }
134 | File[] dirs = parentDir.listFiles((dir, name) -> NodeFinder.structureNodeVersionStr(name) != null);
135 | if (dirs == null || dirs.length == 0) {
136 | return Collections.emptyList();
137 | }
138 | Arrays.sort(dirs, (dir1, dir2) -> {
139 | int[] v1 = NodeFinder.structureNodeVersionStr(dir1.getName());
140 | int[] v2 = NodeFinder.structureNodeVersionStr(dir2.getName());
141 | if (v1 != null && v2 != null) {
142 | for (int i = 0; i < v1.length; i++) {
143 | if (i < v2.length) {
144 | int cmp = v2[i] - v1[i];
145 | if (cmp != 0) {
146 | return cmp;
147 | }
148 | }
149 | }
150 | }
151 | return dir1.getName().compareTo(dir2.getName());
152 | });
153 | List interpreters = ContainerUtil.newArrayListWithCapacity(dirs.length);
154 | for (File dir : dirs) {
155 | File interpreter = new File(dir, "bin" + File.separator + exeFileName);
156 | if (interpreter.isFile() && interpreter.canExecute()) {
157 | interpreters.add(interpreter);
158 | }
159 | }
160 | return interpreters;
161 | }
162 |
163 | @Nullable
164 | private static int[] structureNodeVersionStr(@NotNull String name) {
165 | Matcher matcher = NVM_NODE_DIR_NAME_PATTERN.matcher(name);
166 | if (matcher.matches() && matcher.groupCount() == 3) {
167 | try {
168 | return new int[]{Integer.parseInt(matcher.group(1)), Integer.parseInt(matcher.group(2)), Integer.parseInt(matcher.group(3))};
169 | } catch (Exception ignored) {
170 | }
171 | }
172 | return null;
173 | }
174 |
175 | // public static File find(File projectRoot, String exe) {
176 | // if (SystemInfo.isWindows) {
177 | // File file = NodeFinder.resolvePath(projectRoot, NodeFinder.NODE_MODULES, ".bin", exe);
178 | // if (file.exists()) {
179 | // return file;
180 | // }
181 | // } else {
182 | // File file = NodeFinder.resolvePath(projectRoot, NodeFinder.NODE_MODULES, "grunt-packages", "bin", "packages.js");
183 | // if (file.exists()) {
184 | // return file;
185 | // }
186 | // }
187 | // return null;
188 | // }
189 |
190 | /**
191 | * search for projectRoot/node_modules/.bin/exe
192 | * @param projectRoot node modules root
193 | * @param exe exe to find
194 | * @return file
195 | */
196 | public static File findExeInProjectBin(File projectRoot, String exe) {
197 | File file = NodeFinder.resolvePath(projectRoot, NodeFinder.NODE_MODULES, ".bin", exe);
198 | if (file.exists()) {
199 | return file;
200 | }
201 | return null;
202 | }
203 | }
--------------------------------------------------------------------------------
/intellij-common/src/main/java/com/wix/nodejs/NodeRunner.java:
--------------------------------------------------------------------------------
1 | package com.wix.nodejs;
2 |
3 | import com.google.common.base.Charsets;
4 | import com.intellij.execution.ExecutionException;
5 | import com.intellij.execution.configurations.GeneralCommandLine;
6 | import com.intellij.execution.process.*;
7 | import com.intellij.openapi.diagnostic.Logger;
8 | import com.intellij.openapi.util.Key;
9 | import com.intellij.openapi.util.SystemInfo;
10 | import org.jetbrains.annotations.NotNull;
11 |
12 | import java.io.File;
13 | import java.util.concurrent.TimeUnit;
14 |
15 | public final class NodeRunner {
16 | private NodeRunner() {
17 | }
18 |
19 | private static final Logger LOG = Logger.getInstance(NodeRunner.class);
20 |
21 | private static final int TIME_OUT = (int) TimeUnit.SECONDS.toMillis(120L);
22 |
23 | /**
24 | * @param cwd working directory
25 | * @param node node interpreter path
26 | * @param exe node executable to run
27 | * @return command line to execute
28 | */
29 | @NotNull
30 | public static GeneralCommandLine createCommandLine(@NotNull String cwd, String node, String exe) {
31 | GeneralCommandLine commandLine = new GeneralCommandLine();
32 | if (!new File(cwd).exists() || !new File(exe).exists()) {
33 | throw new IllegalArgumentException("path doesn't exist");
34 | }
35 | commandLine.setWorkDirectory(cwd);
36 | if (SystemInfo.isWindows) {
37 | commandLine.setExePath(exe);
38 | } else {
39 | if (!new File(node).exists()) {
40 | throw new IllegalArgumentException("path doesn't exist");
41 | }
42 | commandLine.setExePath(node);
43 | commandLine.addParameter(exe);
44 | }
45 | return commandLine;
46 | }
47 |
48 |
49 | /**
50 | * @param commandLine command line to execute
51 | * @param timeoutInMilliseconds timeout
52 | * @return process output
53 | * @throws ExecutionException
54 | */
55 | @NotNull
56 | public static ProcessOutput execute(@NotNull GeneralCommandLine commandLine, int timeoutInMilliseconds) throws ExecutionException {
57 | LOG.info("Running node command: " + commandLine.getCommandLineString());
58 | Process process = commandLine.createProcess();
59 | OSProcessHandler processHandler = new ColoredProcessHandler(process, commandLine.getCommandLineString(), Charsets.UTF_8);
60 | final ProcessOutput output = new ProcessOutput();
61 | processHandler.addProcessListener(new ProcessAdapter() {
62 | public void onTextAvailable(@NotNull ProcessEvent event, @NotNull Key outputType) {
63 | if (outputType.equals(ProcessOutputTypes.STDERR)) {
64 | output.appendStderr(event.getText());
65 | } else if (!outputType.equals(ProcessOutputTypes.SYSTEM)) {
66 | output.appendStdout(event.getText());
67 | }
68 | }
69 | });
70 | processHandler.startNotify();
71 | if (processHandler.waitFor(timeoutInMilliseconds)) {
72 | output.setExitCode(process.exitValue());
73 | } else {
74 | processHandler.destroyProcess();
75 | output.setTimeout();
76 | }
77 | if (output.isTimeout()) {
78 | throw new ExecutionException("Command '" + commandLine.getCommandLineString() + "' is timed out.");
79 | }
80 | return output;
81 | }
82 | }
--------------------------------------------------------------------------------
/intellij-common/src/main/java/com/wix/settings/ValidationInfo.java:
--------------------------------------------------------------------------------
1 | package com.wix.settings;
2 |
3 | import com.intellij.openapi.diagnostic.Logger;
4 | import org.jetbrains.annotations.NotNull;
5 | import org.jetbrains.annotations.Nullable;
6 |
7 | import javax.swing.text.JTextComponent;
8 |
9 | public class ValidationInfo {
10 | public static final String LINK_TEMPLATE = "{{LINK}}";
11 | private static final Logger LOG = Logger.getInstance(ValidationInfo.class);
12 | private final JTextComponent textComponent;
13 | private final String errorHtmlDescription;
14 | private final String linkText;
15 |
16 | public ValidationInfo(@Nullable JTextComponent textComponent, @NotNull String errorHtmlDescriptionTemplate, @NotNull String linkText) {
17 | this.textComponent = textComponent;
18 | if (!errorHtmlDescriptionTemplate.contains(LINK_TEMPLATE)) {
19 | LOG.warn("Cannot find {{LINK}} in " + errorHtmlDescriptionTemplate);
20 | }
21 | String linkHtml = "" + linkText + "";
22 | this.errorHtmlDescription = errorHtmlDescriptionTemplate.replace(LINK_TEMPLATE, linkHtml);
23 | this.linkText = linkText;
24 | }
25 |
26 | @Nullable
27 | public JTextComponent getTextComponent() {
28 | return this.textComponent;
29 | }
30 |
31 | @NotNull
32 | public String getErrorHtmlDescription() {
33 | return this.errorHtmlDescription;
34 | }
35 |
36 | @Nullable
37 | public String getLinkText() {
38 | return this.linkText;
39 | }
40 | }
--------------------------------------------------------------------------------
/intellij-common/src/main/java/com/wix/settings/ValidationUtils.java:
--------------------------------------------------------------------------------
1 | package com.wix.settings;
2 |
3 | import com.google.common.base.Strings;
4 | import com.intellij.openapi.project.Project;
5 | import com.intellij.openapi.vfs.VirtualFile;
6 | //import org.apache.commons.lang.StringUtils;
7 |
8 | import java.io.File;
9 |
10 | public final class ValidationUtils {
11 |
12 | private ValidationUtils() {
13 | }
14 |
15 | public static boolean validatePath(Project project, String path, boolean allowEmpty) {
16 | if (Strings.isNullOrEmpty(path)) {
17 | return allowEmpty;
18 | }
19 | File filePath = new File(path);
20 | if (filePath.isAbsolute()) {
21 | if (!filePath.exists() || !filePath.isFile()) {
22 | return false;
23 | }
24 | } else {
25 | if (project == null || project.getBaseDir() == null) {
26 | return true;
27 | }
28 | VirtualFile child = project.getBaseDir().findFileByRelativePath(path);
29 | if (child == null || !child.exists() || child.isDirectory()) {
30 | return false;
31 | }
32 | }
33 | return true;
34 | }
35 |
36 | public static boolean validateDirectory(Project project, String path, boolean allowEmpty) {
37 | if (Strings.isNullOrEmpty(path)) {
38 | return allowEmpty;
39 | }
40 | File filePath = new File(path);
41 | if (filePath.isAbsolute()) {
42 | if (!filePath.exists() || !filePath.isDirectory()) {
43 | return false;
44 | }
45 | } else {
46 | VirtualFile child = project.getBaseDir().findFileByRelativePath(path);
47 | if (child == null || !child.exists() || !child.isDirectory()) {
48 | return false;
49 | }
50 | }
51 | return true;
52 | }
53 | }
54 |
--------------------------------------------------------------------------------
/intellij-common/src/main/java/com/wix/settings/Validator.java:
--------------------------------------------------------------------------------
1 | package com.wix.settings;
2 |
3 | import javax.swing.*;
4 | import java.util.ArrayList;
5 | import java.util.List;
6 |
7 | public class Validator {
8 |
9 | private final List errs = new ArrayList<>();
10 |
11 | public boolean hasErrors() {
12 | return !errs.isEmpty();
13 | }
14 |
15 | public void add(JTextField textEditor, String s, String fixIt) {
16 | errs.add(new ValidationInfo(textEditor, s, fixIt));
17 | }
18 |
19 | public List getErrors() {
20 | return errs;
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/intellij-common/src/main/java/com/wix/utils/FileUtils.java:
--------------------------------------------------------------------------------
1 | package com.wix.utils;
2 |
3 | import com.google.common.base.Strings;
4 | import com.intellij.openapi.diagnostic.Logger;
5 | import com.intellij.openapi.project.Project;
6 | import com.intellij.openapi.util.io.FileUtil;
7 | import com.intellij.openapi.util.text.StringUtil;
8 | import com.intellij.openapi.vfs.VfsUtil;
9 | import com.intellij.openapi.vfs.VfsUtilCore;
10 | import com.intellij.openapi.vfs.VirtualFile;
11 | import com.intellij.openapi.vfs.VirtualFileVisitor;
12 | import com.intellij.openapi.vfs.newvfs.impl.VirtualDirectoryImpl;
13 | import com.intellij.openapi.vfs.newvfs.impl.VirtualFileImpl;
14 | import com.intellij.psi.PsiFile;
15 | import com.intellij.util.Function;
16 | import com.intellij.util.SmartList;
17 | import com.intellij.util.containers.ContainerUtil;
18 | //import com.scss.ScssLintBundle;
19 | import com.wix.Util;
20 | //import org.apache.commons.lang.StringUtils;
21 | import org.jetbrains.annotations.NotNull;
22 | import org.jetbrains.annotations.Nullable;
23 |
24 | import java.io.File;
25 | import java.io.FilenameFilter;
26 | import java.util.ArrayList;
27 | import java.util.Collections;
28 | import java.util.List;
29 |
30 | public final class FileUtils {
31 | private FileUtils() {
32 | }
33 |
34 | private static final Logger LOG = Logger.getInstance(Util.LOG_ID);
35 |
36 | // WildcardFileNameMatcher w = new WildcardFileNameMatcher("**/.jscsrc");
37 |
38 | public static String makeRelative(VirtualFile root, VirtualFile absolutePath) {
39 | //FileUtil.getRelativePath(path, file.getPath().replace('/', File.separatorChar), File.separatorChar)
40 | return VfsUtil.getRelativePath(absolutePath, root, File.separatorChar);
41 | }
42 |
43 | public static String makeRelative(Project project, VirtualFile absolutePath) {
44 | //FileUtil.getRelativePath(path, file.getPath().replace('/', File.separatorChar), File.separatorChar)
45 | return makeRelative(project.getBaseDir(), absolutePath);
46 | }
47 |
48 | public static String relativePath(String root, String path) {
49 | return FileUtil.getRelativePath(new File(root), new File(path));
50 | }
51 |
52 | public static String relativePath(Project project, VirtualFile absolutePath) {
53 | return FileUtil.getRelativePath(new File(project.getBasePath()), new File(absolutePath.getPath()));
54 | }
55 |
56 | public static String relativePath(PsiFile file) {
57 | return FileUtil.getRelativePath(new File(file.getProject().getBasePath()), new File(file.getVirtualFile().getPath()));
58 | }
59 |
60 | public static String getExtensionWithDot(VirtualFile file){
61 | String ext = StringUtil.notNullize(file.getExtension());
62 | if (!ext.startsWith(".")) {
63 | ext = '.' + ext;
64 | }
65 | return ext;
66 | }
67 |
68 | public static String makeRelative(File project, File absolutePath) {
69 | return FileUtil.getRelativePath(project, absolutePath);
70 | }
71 |
72 | public static boolean hasExtension(String file, String extension) {
73 | return file.endsWith(extension);
74 | }
75 |
76 | public static String removeExtension(String file) {
77 | int i = file.lastIndexOf('.');
78 | return file.substring(0, i);
79 | }
80 |
81 | //file.substring(0, file.length() - ".js".length())
82 |
83 | /**
84 | * resolve a relative or absolute path
85 | * @param project parent path
86 | * @param path path to file / folder
87 | * @return path
88 | */
89 | public static String resolvePath(Project project, String path) {
90 | if (Strings.isNullOrEmpty(path)) {
91 | return null;
92 | }
93 | File filePath = new File(path);
94 | if (filePath.isAbsolute()) {
95 | if (!filePath.exists()) {
96 | return null;
97 | }
98 | return path;
99 | } else {
100 | if (project == null) {
101 | return null;
102 | }
103 | VirtualFile child = project.getBaseDir().findFileByRelativePath(path);
104 | if (child == null || !child.exists()) {
105 | return null;
106 | }
107 | return child.getPath();
108 | }
109 | }
110 |
111 | @NotNull
112 | public static List displayDirectoryContents(@NotNull File projectRoot, @NotNull File dir, @NotNull FilenameFilter filter) {
113 | List ret = listFiles(projectRoot, dir, filter);
114 | File[] files = dir.listFiles();
115 | for (final File file : files) {
116 | if (file.isDirectory()) {
117 | ret.addAll(displayDirectoryContents(projectRoot, file, filter));
118 | // } else {
119 | // listFiles(file, filter, allFiles);
120 | }
121 | }
122 | return ret;
123 | }
124 |
125 | @NotNull
126 | public static List recursiveVisitor(@NotNull File dir, @NotNull FilenameFilter filter) {
127 | // String[] ret = dir.list(filter);
128 | List retList = new ArrayList<>();
129 | // Collections.addAll(retList, ret);
130 | File[] files = dir.listFiles();
131 | for (final File file : files) {
132 | if (file.isDirectory()) {
133 | retList.addAll(recursiveVisitor(file, filter));
134 | } else {
135 | if (filter.accept(file.getParentFile(), file.getName())){
136 | retList.add(file.getAbsolutePath());
137 | }
138 | }
139 | }
140 | return retList;
141 | }
142 |
143 | public static List toAbsolutePath(List newFiles) {
144 | return ContainerUtil.map(newFiles, File::getAbsolutePath);
145 | }
146 |
147 | @NotNull
148 | public static List listFiles(@NotNull final File projectRoot, @NotNull final File dir, @NotNull FilenameFilter filter) {
149 | String[] curFiles = dir.list(filter);
150 | // allFiles.addAll(ret); //Arrays.asList(curFiles));
151 | return ContainerUtil.map(curFiles, curFile -> {
152 | // TODO replace with makeRelative
153 | // return makeRelative();
154 | return new File(dir, curFile).getAbsolutePath().substring(projectRoot.getAbsolutePath().length() + 1);
155 | });
156 | }
157 |
158 | @NotNull
159 | private static List findExeFilesInPath(@Nullable String pathEnvVarValue,
160 | @NotNull String fileBaseName,
161 | boolean stopAfterFirstMatch,
162 | boolean logDetails) {
163 | if (logDetails) {
164 | LOG.info("Finding files in PATH (base name=" + fileBaseName + ", PATH=" + StringUtil.notNullize(pathEnvVarValue) + ").");
165 | }
166 | if (pathEnvVarValue == null) {
167 | return Collections.emptyList();
168 | }
169 | List result = new SmartList<>();
170 | List paths = StringUtil.split(pathEnvVarValue, File.pathSeparator, true, true);
171 | for (String path : paths) {
172 | File dir = new File(path);
173 | if (logDetails) {
174 | File file = new File(dir, fileBaseName);
175 | LOG.info("path:" + path + ", path.isAbsolute:" + dir.isAbsolute() + ", path.isDirectory:" + dir.isDirectory()
176 | + ", file.isFile:" + file.isFile() + ", file.canExecute:" + file.canExecute());
177 | }
178 | if (dir.isAbsolute() && dir.isDirectory()) {
179 | File file = new File(dir, fileBaseName);
180 | if (file.isFile() && file.canExecute()) {
181 | result.add(file);
182 | if (stopAfterFirstMatch) {
183 | return result;
184 | }
185 | }
186 | }
187 | }
188 | return result;
189 | }
190 |
191 | /**
192 | *
193 | * @param project containing project
194 | * @param path path to path to file / folder
195 | * @param allowEmpty allow empty path
196 | * @param isFile should be file or folder
197 | * @return validation status
198 | */
199 | public static ValidationStatus validateProjectPath(Project project, String path, boolean allowEmpty, boolean isFile) {
200 | if (Strings.isNullOrEmpty(path)) {
201 | return allowEmpty ? ValidationStatus.VALID : ValidationStatus.IS_EMPTY;
202 | }
203 | File filePath = new File(path);
204 | if (filePath.isAbsolute()) {
205 | if (!filePath.exists()) {
206 | return ValidationStatus.DOES_NOT_EXIST;
207 | }
208 | if (isFile) {
209 | if (!filePath.isFile()) {
210 | return ValidationStatus.NOT_A_FILE;
211 | }
212 | } else {
213 | if (!filePath.isDirectory()) {
214 | return ValidationStatus.NOT_A_DIRECTORY;
215 | }
216 | }
217 | } else {
218 | if (project == null) {
219 | return ValidationStatus.DOES_NOT_EXIST;
220 | }
221 | VirtualFile child = project.getBaseDir().findFileByRelativePath(path);
222 | if (child == null || !child.exists()) {
223 | return ValidationStatus.DOES_NOT_EXIST;
224 | }
225 | if (isFile) {
226 | if (child.isDirectory()) {
227 | return ValidationStatus.NOT_A_FILE;
228 | }
229 | } else {
230 | if (!child.isDirectory()) {
231 | return ValidationStatus.NOT_A_DIRECTORY;
232 | }
233 | }
234 | }
235 | return ValidationStatus.VALID;
236 | }
237 |
238 | // public static class ValidationError {
239 | // public boolean a;
240 | // }
241 | //
242 | public enum ValidationStatus {
243 | VALID, IS_EMPTY, DOES_NOT_EXIST, NOT_A_DIRECTORY, NOT_A_FILE
244 | }
245 |
246 | public static boolean fileExists(String path) {
247 | if (Strings.isNullOrEmpty(path)) {
248 | return false;
249 | }
250 | File file = new File(path);
251 | return file.isFile() && file.exists();
252 | }
253 |
254 | public static List getAllFilesInDirectory(VirtualFile directory, String target, String replacement) {
255 | List files = new ArrayList<>();
256 |
257 | final VirtualFileVisitor fileVisitor = new VirtualFileVisitor(VirtualFileVisitor.SKIP_ROOT, VirtualFileVisitor.NO_FOLLOW_SYMLINKS) {
258 | @Override
259 | public boolean visitFile(@NotNull VirtualFile file) {
260 | // if (file instanceof VirtualDirectoryImpl) {
261 | // files.addAll(getAllFilesInDirectory(file, target, replacement));
262 | // } else if (child instanceof VirtualFileImpl) {
263 | files.add(file.getPath().replace(target, replacement));
264 | // }
265 | // if (ApplicationDictionary.SUPPORTED_APPLICATION_EXTENSIONS.contains(file.getExtension())) {
266 | // if (applicationName.equals(file.getNameWithoutExtension())) {
267 | // throw new MyStopVisitingException(file);
268 | // }
269 | // return false; //do not search inside application bundles
270 | // }
271 | // return true;
272 | }
273 | };
274 | VfsUtilCore.visitChildrenRecursively(directory, fileVisitor)
275 | // VirtualFile[] children = directory.getChildren();
276 | // for (VirtualFile child : children) {
277 | // if (child instanceof VirtualDirectoryImpl) {
278 | // files.addAll(getAllFilesInDirectory(child, target, replacement));
279 | // } else if (child instanceof VirtualFileImpl) {
280 | // files.add(child.getPath().replace(target, replacement));
281 | // }
282 | // }
283 | return files;
284 | }
285 |
286 | public static VirtualFile findFileByPath(VirtualFile path, String valuePath) {
287 | VirtualFile file = path.findFileByRelativePath(valuePath);
288 | if (null == file || file.isDirectory()) {
289 | file = path.findFileByRelativePath(valuePath + ".js");
290 | }
291 | return file;
292 | }
293 |
294 |
295 | public static String join(String file, String ext) {
296 | return file + '/' + ext;
297 | }
298 |
299 | public static String removeExt(String file, String ext) {
300 | if (file.endsWith(ext)) {
301 | return file.replace(ext, "");
302 | }
303 | return file;
304 | }
305 |
306 | public static String relativePath(VirtualFile root, VirtualFile file) {
307 | // get project relative path
308 | return file.getPath().substring(root.getPath().length() + 1);
309 | }
310 |
311 | public static String getNormalizedPath(int doubleDotCount, String[] pathsOfPath) {
312 | StringBuilder newValuePath = new StringBuilder();
313 | for (int i = 0; i < pathsOfPath.length - doubleDotCount; i++) {
314 | if (0 != i) {
315 | newValuePath.append('/');
316 | }
317 | newValuePath.append(pathsOfPath[i]);
318 | }
319 | return newValuePath.toString();
320 | }
321 |
322 | public static int getDoubleDotCount(String valuePath) {
323 | int doubleDotCount = (valuePath.length() - valuePath.replaceAll("\\.\\.", "").length()) / 2;
324 | boolean doubleDotCountTrues = false;
325 |
326 | while (!doubleDotCountTrues && 0 != doubleDotCount) {
327 | if (valuePath.startsWith(StringUtil.repeat("../", doubleDotCount)) || valuePath.startsWith(StringUtil.repeat("../", doubleDotCount - 1) + "..")) {
328 | doubleDotCountTrues = true;
329 | } else {
330 | doubleDotCount--;
331 | }
332 | }
333 | return doubleDotCount;
334 | }
335 | }
336 |
--------------------------------------------------------------------------------
/intellij-common/src/main/java/com/wix/utils/PsiUtil.java:
--------------------------------------------------------------------------------
1 | package com.wix.utils;
2 |
3 | import com.intellij.openapi.editor.Document;
4 | import com.intellij.psi.PsiElement;
5 | import com.intellij.psi.PsiFile;
6 | import org.jetbrains.annotations.NotNull;
7 |
8 | /**
9 | * Psi Utils
10 | * Created by idok on 6/26/14.
11 | */
12 | public final class PsiUtil {
13 | private PsiUtil() {
14 | }
15 |
16 | /**
17 | * copied from com.intellij.psi.util.PsiUtilCore to fix compatibility issue with webstorm
18 | * @param file psi file
19 | * @param offset offset to search
20 | * @return psi element in the offset
21 | */
22 | @NotNull
23 | public static PsiElement getElementAtOffset(@NotNull PsiFile file, int offset) {
24 | PsiElement elt = file.findElementAt(offset);
25 | if (elt == null && offset > 0) {
26 | elt = file.findElementAt(offset - 1);
27 | }
28 | if (elt == null) {
29 | return file;
30 | }
31 | return elt;
32 | }
33 |
34 | public static int calcErrorStartOffsetInDocument(@NotNull Document document, int lineStartOffset, int lineEndOffset, int column, int tabSize) {
35 | if (tabSize <= 1) {
36 | if (column < 0) {
37 | return lineStartOffset;
38 | }
39 | return Math.min(lineStartOffset + column, lineEndOffset);
40 | }
41 | CharSequence docText = document.getCharsSequence();
42 | int offset = lineStartOffset;
43 | int col = 0;
44 | while (offset < lineEndOffset && col < column) {
45 | col += docText.charAt(offset) == '\t' ? tabSize : 1;
46 | offset++;
47 | }
48 | return offset;
49 | }
50 |
51 | public static int positionToOffset(@NotNull Document document, int line, int column, int tabSize) {
52 | int errorLine = line - 1;
53 | int errorColumn = column /*- 1*/;
54 |
55 | if (errorLine < 0 || errorLine >= document.getLineCount()) {
56 | return -1;
57 | }
58 | int lineEndOffset = document.getLineEndOffset(errorLine);
59 | int lineStartOffset = document.getLineStartOffset(errorLine);
60 |
61 | return calcErrorStartOffsetInDocument(document, lineStartOffset, lineEndOffset, errorColumn, tabSize);
62 | }
63 |
64 | // @Nullable
65 | // private static TextRange findRangeInDocument(@NotNull PsiFile file, @NotNull Document document, int line, int column,
66 | // int tabSize, boolean showErrorOnWholeLine) {
67 | // if (line < 0 || line >= document.getLineCount()) {
68 | // return null;
69 | // }
70 | // int lineEndOffset = document.getLineEndOffset(line);
71 | // int lineStartOffset = document.getLineStartOffset(line);
72 | //
73 | // int errorLineStartOffset = calcErrorStartOffsetInDocument(document, lineStartOffset, lineEndOffset, column, tabSize);
74 | //
75 | // if (errorLineStartOffset == -1) {
76 | // return null;
77 | // }
78 | // PsiElement element = file.findElementAt(errorLineStartOffset);
79 | //// if (element != null /*&& JSInspection.isSuppressedForStatic(element, getInspectionClass(), inspectionKey.getID())*/)
80 | //// return null;
81 | // TextRange range;
82 | // if (showErrorOnWholeLine) {
83 | // range = new TextRange(lineStartOffset, lineEndOffset);
84 | // } else {
85 | //// int offset = StringUtil.lineColToOffset(document.getText(), warn.line - 1, warn.column);
86 | // PsiElement lit = PsiUtil.getElementAtOffset(file, errorLineStartOffset);
87 | // range = lit.getTextRange();
88 | //// range = new TextRange(errorLineStartOffset, errorLineStartOffset + 1);
89 | // }
90 | // return new TextRange(errorLineStartOffset, errorLineStartOffset + issue.length);
91 | // }
92 | }
93 |
--------------------------------------------------------------------------------
/intellij-common/src/main/java/com/wix/utils/Strings.java:
--------------------------------------------------------------------------------
1 | package com.wix.utils;
2 |
3 | public final class Strings {
4 | private Strings() {
5 | }
6 |
7 | public static boolean areEqual(String a, String b) {
8 | if (a == null) {
9 | return b == null;
10 | }
11 | return a.equals(b);
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/scss-lint-plugin/.gitignore:
--------------------------------------------------------------------------------
1 | # /**/*.iml
2 | /target
3 | /.idea
4 |
5 | # Created by http://www.gitignore.io
6 |
7 | ### Intellij ###
8 | # Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm
9 |
10 | ## Directory-based project format
11 | .idea/
12 | # if you remove the above rule, at least ignore user-specific stuff:
13 | # .idea/workspace.xml
14 | # .idea/tasks.xml
15 | # and these sensitive or high-churn files:
16 | # .idea/dataSources.ids
17 | # .idea/dataSources.xml
18 | # .idea/sqlDataSources.xml
19 | # .idea/dynamic.xml
20 |
21 | ## File-based project format
22 | *.ipr
23 | *.iws
24 | *.iml
25 |
26 | ## Additional for IntelliJ
27 | out/
28 |
29 | # generated by mpeltonen/sbt-idea plugin
30 | .idea_modules/
31 |
32 | # generated by JIRA plugin
33 | atlassian-ide-plugin.xml
34 |
35 | # generated by Crashlytics plugin (for Android Studio and Intellij)
36 | com_crashlytics_export_strings.xml
37 |
38 |
39 | ### OSX ###
40 | .DS_Store
41 | .AppleDouble
42 | .LSOverride
43 |
44 | # Icon must ends with two \r.
45 | Icon
46 |
47 |
48 | # Thumbnails
49 | ._*
50 |
51 | # Files that might appear on external disk
52 | .Spotlight-V100
53 | .Trashes
54 |
55 | # gradle
56 | .gradle
57 | /build
58 | gradle.properties
59 |
60 | node_modules
61 | coverage
62 | target
63 | npm-debug.log
64 |
65 | /temp
--------------------------------------------------------------------------------
/scss-lint-plugin/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2014 Idok
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy of
6 | this software and associated documentation files (the "Software"), to deal in
7 | the Software without restriction, including without limitation the rights to
8 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
9 | the Software, and to permit persons to whom the Software is furnished to do so,
10 | subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
17 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
18 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
19 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
20 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21 |
--------------------------------------------------------------------------------
/scss-lint-plugin/build.gradle:
--------------------------------------------------------------------------------
1 |
2 | plugins {
3 | id 'java'
4 | id 'org.jetbrains.intellij' version '0.4.10'
5 | id 'org.jetbrains.kotlin.jvm' version '1.3.41'
6 | }
7 |
8 | group pluginGroup
9 | version pluginVersion
10 |
11 | sourceCompatibility = javaVersion
12 | targetCompatibility = javaTargetVersion
13 |
14 | repositories {
15 | mavenCentral()
16 | // jcenter()
17 | }
18 |
19 | dependencies {
20 | testCompile group: 'junit', name: 'junit', version: '4.12'
21 | // compile (name:'com.wix.intellij-common', ext:'aar')
22 | // compile name: 'intellij-common'
23 | // compile project('intellij-common')
24 | compile files('../intellij-common/build/libs/intellij-common-1.0-SNAPSHOT.jar')
25 | compile 'com.google.code.gson:gson:2.8.5', 'com.esotericsoftware.yamlbeans:yamlbeans:1.08'
26 | //, files('./lib/gson-2.3.1.jar')
27 | }
28 |
29 | // See https://github.com/JetBrains/gradle-intellij-plugin/
30 | intellij {
31 | pluginName 'scss-lint'
32 | localPath '/Users/idok/Library/Application Support/JetBrains/Toolbox/apps/IDEA-U/ch-0/192.6262.9/IntelliJ IDEA 2019.2 EAP.app'
33 | // alternativeIdePath idePath
34 | // version '192.5728.98'
35 | // type 'IU'
36 | // version 'IC-2018.3'
37 | // plugins = [project(':intellij-common')]
38 | // plugins = ['coverage', 'org.intellij.plugins.markdown:8.5.0.20160208']
39 | plugins = ['CSS']
40 | updateSinceUntilBuild false
41 | sameSinceUntilBuild true
42 | }
43 |
44 | publishPlugin {
45 | token intellijPublishToken
46 | channels publishChannel
47 | }
48 |
49 | patchPluginXml {
50 | // changeNotes """
51 | // Add change notes here.
52 | // most HTML tags may be used"""
53 | }
54 |
55 |
--------------------------------------------------------------------------------
/scss-lint-plugin/docs/Inspection.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/idok/scss-lint-plugin/78aa47c12927d5dbdb99ba48052b242d4ec4fdb5/scss-lint-plugin/docs/Inspection.png
--------------------------------------------------------------------------------
/scss-lint-plugin/docs/PropertySortRule.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/idok/scss-lint-plugin/78aa47c12927d5dbdb99ba48052b242d4ec4fdb5/scss-lint-plugin/docs/PropertySortRule.png
--------------------------------------------------------------------------------
/scss-lint-plugin/docs/Rule.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/idok/scss-lint-plugin/78aa47c12927d5dbdb99ba48052b242d4ec4fdb5/scss-lint-plugin/docs/Rule.png
--------------------------------------------------------------------------------
/scss-lint-plugin/docs/Settings.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/idok/scss-lint-plugin/78aa47c12927d5dbdb99ba48052b242d4ec4fdb5/scss-lint-plugin/docs/Settings.png
--------------------------------------------------------------------------------
/scss-lint-plugin/gradlew:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env sh
2 |
3 | ##############################################################################
4 | ##
5 | ## Gradle start up script for UN*X
6 | ##
7 | ##############################################################################
8 |
9 | # Attempt to set APP_HOME
10 | # Resolve links: $0 may be a link
11 | PRG="$0"
12 | # Need this for relative symlinks.
13 | while [ -h "$PRG" ] ; do
14 | ls=`ls -ld "$PRG"`
15 | link=`expr "$ls" : '.*-> \(.*\)$'`
16 | if expr "$link" : '/.*' > /dev/null; then
17 | PRG="$link"
18 | else
19 | PRG=`dirname "$PRG"`"/$link"
20 | fi
21 | done
22 | SAVED="`pwd`"
23 | cd "`dirname \"$PRG\"`/" >/dev/null
24 | APP_HOME="`pwd -P`"
25 | cd "$SAVED" >/dev/null
26 |
27 | APP_NAME="Gradle"
28 | APP_BASE_NAME=`basename "$0"`
29 |
30 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
31 | DEFAULT_JVM_OPTS='"-Xmx64m"'
32 |
33 | # Use the maximum available, or set MAX_FD != -1 to use that value.
34 | MAX_FD="maximum"
35 |
36 | warn () {
37 | echo "$*"
38 | }
39 |
40 | die () {
41 | echo
42 | echo "$*"
43 | echo
44 | exit 1
45 | }
46 |
47 | # OS specific support (must be 'true' or 'false').
48 | cygwin=false
49 | msys=false
50 | darwin=false
51 | nonstop=false
52 | case "`uname`" in
53 | CYGWIN* )
54 | cygwin=true
55 | ;;
56 | Darwin* )
57 | darwin=true
58 | ;;
59 | MINGW* )
60 | msys=true
61 | ;;
62 | NONSTOP* )
63 | nonstop=true
64 | ;;
65 | esac
66 |
67 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
68 |
69 | # Determine the Java command to use to start the JVM.
70 | if [ -n "$JAVA_HOME" ] ; then
71 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
72 | # IBM's JDK on AIX uses strange locations for the executables
73 | JAVACMD="$JAVA_HOME/jre/sh/java"
74 | else
75 | JAVACMD="$JAVA_HOME/bin/java"
76 | fi
77 | if [ ! -x "$JAVACMD" ] ; then
78 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
79 |
80 | Please set the JAVA_HOME variable in your environment to match the
81 | location of your Java installation."
82 | fi
83 | else
84 | JAVACMD="java"
85 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
86 |
87 | Please set the JAVA_HOME variable in your environment to match the
88 | location of your Java installation."
89 | fi
90 |
91 | # Increase the maximum file descriptors if we can.
92 | if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
93 | MAX_FD_LIMIT=`ulimit -H -n`
94 | if [ $? -eq 0 ] ; then
95 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
96 | MAX_FD="$MAX_FD_LIMIT"
97 | fi
98 | ulimit -n $MAX_FD
99 | if [ $? -ne 0 ] ; then
100 | warn "Could not set maximum file descriptor limit: $MAX_FD"
101 | fi
102 | else
103 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
104 | fi
105 | fi
106 |
107 | # For Darwin, add options to specify how the application appears in the dock
108 | if $darwin; then
109 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
110 | fi
111 |
112 | # For Cygwin, switch paths to Windows format before running java
113 | if $cygwin ; then
114 | APP_HOME=`cygpath --path --mixed "$APP_HOME"`
115 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
116 | JAVACMD=`cygpath --unix "$JAVACMD"`
117 |
118 | # We build the pattern for arguments to be converted via cygpath
119 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
120 | SEP=""
121 | for dir in $ROOTDIRSRAW ; do
122 | ROOTDIRS="$ROOTDIRS$SEP$dir"
123 | SEP="|"
124 | done
125 | OURCYGPATTERN="(^($ROOTDIRS))"
126 | # Add a user-defined pattern to the cygpath arguments
127 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then
128 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
129 | fi
130 | # Now convert the arguments - kludge to limit ourselves to /bin/sh
131 | i=0
132 | for arg in "$@" ; do
133 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
134 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
135 |
136 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
137 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
138 | else
139 | eval `echo args$i`="\"$arg\""
140 | fi
141 | i=$((i+1))
142 | done
143 | case $i in
144 | (0) set -- ;;
145 | (1) set -- "$args0" ;;
146 | (2) set -- "$args0" "$args1" ;;
147 | (3) set -- "$args0" "$args1" "$args2" ;;
148 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
149 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
150 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
151 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
152 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
153 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
154 | esac
155 | fi
156 |
157 | # Escape application args
158 | save () {
159 | for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
160 | echo " "
161 | }
162 | APP_ARGS=$(save "$@")
163 |
164 | # Collect all arguments for the java command, following the shell quoting and substitution rules
165 | eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
166 |
167 | # by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong
168 | if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then
169 | cd "$(dirname "$0")"
170 | fi
171 |
172 | exec "$JAVACMD" "$@"
173 |
--------------------------------------------------------------------------------
/scss-lint-plugin/gradlew.bat:
--------------------------------------------------------------------------------
1 | @if "%DEBUG%" == "" @echo off
2 | @rem ##########################################################################
3 | @rem
4 | @rem Gradle startup script for Windows
5 | @rem
6 | @rem ##########################################################################
7 |
8 | @rem Set local scope for the variables with windows NT shell
9 | if "%OS%"=="Windows_NT" setlocal
10 |
11 | set DIRNAME=%~dp0
12 | if "%DIRNAME%" == "" set DIRNAME=.
13 | set APP_BASE_NAME=%~n0
14 | set APP_HOME=%DIRNAME%
15 |
16 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
17 | set DEFAULT_JVM_OPTS="-Xmx64m"
18 |
19 | @rem Find java.exe
20 | if defined JAVA_HOME goto findJavaFromJavaHome
21 |
22 | set JAVA_EXE=java.exe
23 | %JAVA_EXE% -version >NUL 2>&1
24 | if "%ERRORLEVEL%" == "0" goto init
25 |
26 | echo.
27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
28 | echo.
29 | echo Please set the JAVA_HOME variable in your environment to match the
30 | echo location of your Java installation.
31 |
32 | goto fail
33 |
34 | :findJavaFromJavaHome
35 | set JAVA_HOME=%JAVA_HOME:"=%
36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe
37 |
38 | if exist "%JAVA_EXE%" goto init
39 |
40 | echo.
41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
42 | echo.
43 | echo Please set the JAVA_HOME variable in your environment to match the
44 | echo location of your Java installation.
45 |
46 | goto fail
47 |
48 | :init
49 | @rem Get command-line arguments, handling Windows variants
50 |
51 | if not "%OS%" == "Windows_NT" goto win9xME_args
52 |
53 | :win9xME_args
54 | @rem Slurp the command line arguments.
55 | set CMD_LINE_ARGS=
56 | set _SKIP=2
57 |
58 | :win9xME_args_slurp
59 | if "x%~1" == "x" goto execute
60 |
61 | set CMD_LINE_ARGS=%*
62 |
63 | :execute
64 | @rem Setup the command line
65 |
66 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
67 |
68 | @rem Execute Gradle
69 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
70 |
71 | :end
72 | @rem End local scope for the variables with windows NT shell
73 | if "%ERRORLEVEL%"=="0" goto mainEnd
74 |
75 | :fail
76 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
77 | rem the _cmd.exe /c_ return code!
78 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
79 | exit /b 1
80 |
81 | :mainEnd
82 | if "%OS%"=="Windows_NT" endlocal
83 |
84 | :omega
85 |
--------------------------------------------------------------------------------
/scss-lint-plugin/lib/xstream-1.4.7.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/idok/scss-lint-plugin/78aa47c12927d5dbdb99ba48052b242d4ec4fdb5/scss-lint-plugin/lib/xstream-1.4.7.jar
--------------------------------------------------------------------------------
/scss-lint-plugin/settings.gradle:
--------------------------------------------------------------------------------
1 | rootProject.name = 'scss-lint'
2 | include 'intellij-common'
3 |
4 |
--------------------------------------------------------------------------------
/scss-lint-plugin/src/log4j-old.properties:
--------------------------------------------------------------------------------
1 |
2 | # Set root logger level to DEBUG and its only appender to A1.
3 | log4j.rootLogger=DEBUG, A1
4 |
5 | log4j.com.eslint=ALL, A1
6 |
7 | # A1 is set to be a ConsoleAppender.
8 | log4j.appender.A1=org.apache.log4j.ConsoleAppender
9 |
10 | # A1 uses PatternLayout.
11 | log4j.appender.A1.layout=org.apache.log4j.PatternLayout
12 | log4j.appender.A1.layout.ConversionPattern=%-4r [%t] %-5p %c %x - %m%n
13 |
14 | #com.intellij.ide.plugins.PluginBean
15 |
--------------------------------------------------------------------------------
/scss-lint-plugin/src/log4j.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
--------------------------------------------------------------------------------
/scss-lint-plugin/src/log4j0.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
--------------------------------------------------------------------------------
/scss-lint-plugin/src/main/java/com/scss/EditSettingsAction.java:
--------------------------------------------------------------------------------
1 | package com.scss;
2 |
3 | import com.intellij.codeInsight.intention.HighPriorityAction;
4 | import com.intellij.codeInsight.intention.IntentionAction;
5 | import com.intellij.icons.AllIcons.General;
6 | import com.intellij.openapi.application.ApplicationManager;
7 | import com.intellij.openapi.application.ModalityState;
8 | import com.intellij.openapi.editor.Editor;
9 | import com.intellij.openapi.project.Project;
10 | import com.intellij.openapi.util.Iconable;
11 | import com.intellij.psi.PsiFile;
12 | import com.intellij.util.IncorrectOperationException;
13 |
14 | import javax.swing.Icon;
15 |
16 | import com.scss.settings.ScssLintSettingsPage;
17 | import org.jetbrains.annotations.NotNull;
18 |
19 | class EditSettingsAction implements IntentionAction, Iconable, HighPriorityAction {
20 | private static boolean ourInvoked;
21 | private final boolean fileLevelAnnotation;
22 | private final Icon icon;
23 | private final ScssLintSettingsPage configurable;
24 |
25 | EditSettingsAction(@NotNull ScssLintSettingsPage configurable) {
26 | this(configurable, false, General.Settings);
27 | }
28 |
29 | public EditSettingsAction(@NotNull ScssLintSettingsPage configurable, @NotNull Icon icon) {
30 | this(configurable, false, icon);
31 | }
32 |
33 | public EditSettingsAction(@NotNull ScssLintSettingsPage configurable, boolean fileLevelAnnotation) {
34 | this(configurable, fileLevelAnnotation, General.Settings);
35 | }
36 |
37 | private EditSettingsAction(@NotNull ScssLintSettingsPage configurable, boolean fileLevelAnnotation, @NotNull Icon icon) {
38 | this.configurable = configurable;
39 | this.fileLevelAnnotation = fileLevelAnnotation;
40 | this.icon = icon;
41 | }
42 |
43 | @NotNull
44 | public Priority getPriority() {
45 | return Priority.HIGH;
46 | }
47 |
48 | public Icon getIcon(@IconFlags int flags) {
49 | return this.icon;
50 | }
51 |
52 | @NotNull
53 | public String getText() {
54 | return this.fileLevelAnnotation ? "Settings..." : this.configurable.getDisplayName() + " settings...";
55 | }
56 |
57 | @NotNull
58 | public String getFamilyName() {
59 | return this.getText();
60 | }
61 |
62 | public boolean isAvailable(@NotNull Project project, Editor editor, PsiFile file) {
63 | return true;
64 | }
65 |
66 | public void invoke(@NotNull Project project, Editor editor, PsiFile file) throws IncorrectOperationException {
67 | if (!ourInvoked) {
68 | ourInvoked = true;
69 | ApplicationManager.getApplication().invokeLater(() -> {
70 | EditSettingsAction.ourInvoked = false;
71 | EditSettingsAction.this.configurable.showSettings();
72 | }, ModalityState.any());
73 | }
74 | }
75 |
76 | public boolean startInWriteAction() {
77 | return false;
78 | }
79 | }
80 |
--------------------------------------------------------------------------------
/scss-lint-plugin/src/main/java/com/scss/ScssLintBundle.java:
--------------------------------------------------------------------------------
1 | package com.scss;
2 |
3 | import com.intellij.CommonBundle;
4 | import org.jetbrains.annotations.NonNls;
5 | import org.jetbrains.annotations.NotNull;
6 | import org.jetbrains.annotations.PropertyKey;
7 |
8 | import java.lang.ref.Reference;
9 | import java.lang.ref.SoftReference;
10 | import java.util.ResourceBundle;
11 |
12 | public final class ScssLintBundle {
13 |
14 | public static String message(@NotNull @PropertyKey(resourceBundle = BUNDLE) String key, @NotNull Object... params) {
15 | return CommonBundle.message(getBundle(), key, params);
16 | }
17 |
18 | @NonNls
19 | public static final String BUNDLE = "com.scss.ScssLintBundle";
20 | private static Reference ourBundle;
21 |
22 | @NonNls
23 | public static final String LOG_ID = "#com.scss";
24 |
25 | private ScssLintBundle() {
26 | }
27 |
28 | private static ResourceBundle getBundle() {
29 | ResourceBundle bundle = com.intellij.reference.SoftReference.dereference(ourBundle);
30 | if (bundle == null) {
31 | bundle = ResourceBundle.getBundle(BUNDLE);
32 | ourBundle = new SoftReference<>(bundle);
33 | }
34 | return bundle;
35 | }
36 | }
--------------------------------------------------------------------------------
/scss-lint-plugin/src/main/java/com/scss/ScssLintExternalAnnotator.java:
--------------------------------------------------------------------------------
1 | package com.scss;
2 |
3 | import com.intellij.codeInsight.daemon.HighlightDisplayKey;
4 | import com.intellij.codeInsight.daemon.impl.SeverityRegistrar;
5 | import com.intellij.lang.annotation.Annotation;
6 | import com.intellij.lang.annotation.AnnotationHolder;
7 | import com.intellij.lang.annotation.ExternalAnnotator;
8 | import com.intellij.lang.annotation.HighlightSeverity;
9 | import com.intellij.notification.NotificationType;
10 | import com.intellij.openapi.diagnostic.Logger;
11 | import com.intellij.openapi.editor.Document;
12 | import com.intellij.openapi.editor.Editor;
13 | import com.intellij.openapi.editor.colors.EditorColorsScheme;
14 | import com.intellij.openapi.editor.markup.TextAttributes;
15 | import com.intellij.openapi.project.Project;
16 | import com.intellij.openapi.util.Key;
17 | import com.intellij.openapi.util.TextRange;
18 | import com.intellij.openapi.util.io.FileUtil;
19 | import com.intellij.openapi.util.text.StringUtil;
20 | import com.intellij.openapi.vfs.VirtualFile;
21 | import com.intellij.profile.codeInspection.InspectionProjectProfileManager;
22 | import com.intellij.psi.MultiplePsiFilesPerDocumentFileViewProvider;
23 | import com.intellij.psi.PsiDocumentManager;
24 | import com.intellij.psi.PsiElement;
25 | import com.intellij.psi.PsiFile;
26 | import com.scss.annotator.BaseActionFix;
27 | import com.scss.annotator.Fixes;
28 | import com.scss.config.ScssLintConfigFileChangeTracker;
29 | import com.scss.settings.ScssLintSettingsPage;
30 | import com.scss.utils.ScssLintRunner;
31 | import com.scss.utils.scssLint.Lint;
32 | import com.scss.utils.scssLint.LintResult;
33 | import com.wix.annotator.AnnotatorUtils;
34 | import com.wix.files.ActualFileManager;
35 | import com.wix.files.BaseActualFile;
36 | import com.wix.files.TempFile;
37 | import com.wix.files.ThreadLocalTempActualFile;
38 | import com.wix.utils.PsiUtil;
39 | import org.apache.commons.lang.StringUtils;
40 | import org.jetbrains.annotations.NotNull;
41 | import org.jetbrains.annotations.Nullable;
42 |
43 | import java.io.File;
44 | import java.io.IOException;
45 | import java.util.List;
46 |
47 | /**
48 | * @author idok
49 | */
50 | public class ScssLintExternalAnnotator extends ExternalAnnotator {
51 |
52 | // public static final ScssLintExternalAnnotator INSTANCE = new ScssLintExternalAnnotator();
53 | private static final Logger LOG = Logger.getInstance(ScssLintBundle.LOG_ID);
54 | // private static final Key SCSS_TEMP_FILE_KEY = Key.create("SCSS_TEMP_FILE");
55 | public static final String SCSS = "scss";
56 |
57 | @Nullable
58 | @Override
59 | public ScssLintAnnotationInput collectInformation(@NotNull PsiFile file) {
60 | return collectInformation(file, null);
61 | }
62 |
63 | @Nullable
64 | @Override
65 | public ScssLintAnnotationInput collectInformation(@NotNull PsiFile file, @NotNull Editor editor, boolean hasErrors) {
66 | return collectInformation(file, editor);
67 | }
68 |
69 | @NotNull
70 | public static HighlightDisplayKey getHighlightDisplayKeyByClass() {
71 | String id = "ScssLint";
72 | HighlightDisplayKey key = HighlightDisplayKey.find(id);
73 | if (key == null) {
74 | key = new HighlightDisplayKey(id, id);
75 | }
76 | return key;
77 | }
78 |
79 | @Override
80 | public void apply(@NotNull PsiFile file, ScssLintAnnotationResult annotationResult, @NotNull AnnotationHolder holder) {
81 | if (annotationResult == null) {
82 | return;
83 | }
84 | InspectionProjectProfileManager inspectionProjectProfileManager = InspectionProjectProfileManager.getInstance(file.getProject());
85 | SeverityRegistrar severityRegistrar = inspectionProjectProfileManager.getSeverityRegistrar();
86 | HighlightDisplayKey inspectionKey = getHighlightDisplayKeyByClass();
87 | EditorColorsScheme colorsScheme = annotationResult.input.colorsScheme;
88 |
89 | Document document = PsiDocumentManager.getInstance(file.getProject()).getDocument(file);
90 | if (document == null) {
91 | return;
92 | }
93 |
94 | if (annotationResult.fileLevel != null) {
95 | Annotation annotation = holder.createWarningAnnotation(file, annotationResult.fileLevel);
96 | annotation.registerFix(new EditSettingsAction(new ScssLintSettingsPage(file.getProject())));
97 | annotation.setFileLevelAnnotation(true);
98 | return;
99 | }
100 |
101 | // TODO consider adding a fix to edit configuration file
102 | if (annotationResult.result == null || annotationResult.result.lint == null || annotationResult.result.lint.isEmpty()) {
103 | return;
104 | }
105 | // String relativeFile = FileUtils.makeRelative(file.getProject(), file.getVirtualFile());
106 | List issues = annotationResult.result.lint.values().iterator().next();
107 | if (issues == null) {
108 | return;
109 | }
110 | ScssLintProjectComponent component = annotationResult.input.project.getComponent(ScssLintProjectComponent.class);
111 | int tabSize = 4;
112 | for (Lint.Issue issue : issues) {
113 | HighlightSeverity severity = getHighlightSeverity(issue, component.treatAsWarnings);
114 | TextAttributes forcedTextAttributes = AnnotatorUtils.getTextAttributes(colorsScheme, severityRegistrar, severity);
115 | Annotation annotation = createAnnotation(holder, file, document, issue, "SCSS Lint: ", tabSize, severity, forcedTextAttributes, inspectionKey, false);
116 | if (annotation != null) {
117 | int offset = StringUtil.lineColToOffset(document.getText(), issue.line - 1, issue.column);
118 | PsiElement lit = PsiUtil.getElementAtOffset(file, offset);
119 | BaseActionFix actionFix = Fixes.getFixForRule(issue.linter, lit);
120 | if (actionFix != null) {
121 | annotation.registerFix(actionFix, null, inspectionKey);
122 | }
123 | // annotation.registerFix(new SuppressActionFix(issue.rule, lit), null, inspectionKey);
124 | }
125 | }
126 | }
127 |
128 | private static HighlightSeverity getHighlightSeverity(Lint.Issue warn) {
129 | return warn.severity.equals("error") ? HighlightSeverity.ERROR : HighlightSeverity.WARNING;
130 | }
131 |
132 | private static HighlightSeverity getHighlightSeverity(Lint.Issue issue, boolean treatAsWarnings) {
133 | return treatAsWarnings ? HighlightSeverity.WARNING : getHighlightSeverity(issue);
134 | }
135 |
136 | @Nullable
137 | private static Annotation createAnnotation(@NotNull AnnotationHolder holder, @NotNull PsiFile file, @NotNull Document document, @NotNull Lint.Issue issue,
138 | @NotNull String messagePrefix, int tabSize, @NotNull HighlightSeverity severity, @Nullable TextAttributes forcedTextAttributes,
139 | @NotNull HighlightDisplayKey inspectionKey, boolean showErrorOnWholeLine) {
140 | int errorLine = issue.line - 1;
141 | int errorColumn = issue.column - 1;
142 |
143 | if (errorLine < 0 || errorLine >= document.getLineCount()) {
144 | return null;
145 | }
146 | int lineEndOffset = document.getLineEndOffset(errorLine);
147 | int lineStartOffset = document.getLineStartOffset(errorLine);
148 |
149 | int errorLineStartOffset = PsiUtil.calcErrorStartOffsetInDocument(document, lineStartOffset, lineEndOffset, errorColumn, tabSize);
150 |
151 | if (errorLineStartOffset == -1) {
152 | return null;
153 | }
154 | PsiElement element = file.findElementAt(errorLineStartOffset);
155 | // if (element != null /*&& JSInspection.isSuppressedForStatic(element, getInspectionClass(), inspectionKey.getID())*/)
156 | // return null;
157 | TextRange range;
158 | if (showErrorOnWholeLine) {
159 | range = new TextRange(lineStartOffset, lineEndOffset);
160 | } else {
161 | // int offset = StringUtil.lineColToOffset(document.getText(), warn.line - 1, warn.column);
162 | PsiElement lit = PsiUtil.getElementAtOffset(file, errorLineStartOffset);
163 | range = lit.getTextRange();
164 | // range = new TextRange(errorLineStartOffset, errorLineStartOffset + 1);
165 | }
166 | range = new TextRange(errorLineStartOffset, errorLineStartOffset + issue.length);
167 |
168 | Annotation annotation = createAnnotation(holder, severity, forcedTextAttributes, range, messagePrefix + issue.reason.trim() + " (" + (issue.linter == null ? "none" : issue.linter) + ')');
169 | if (annotation != null) {
170 | annotation.setAfterEndOfLine(errorLineStartOffset == lineEndOffset);
171 | }
172 | return annotation;
173 | }
174 |
175 | @NotNull
176 | public static Annotation createAnnotation(@NotNull AnnotationHolder holder, @NotNull HighlightSeverity severity, @NotNull TextRange range, @NotNull String message) {
177 | /*
178 | avoid using
179 | holder.createAnnotation(severity, range, message); as it is not supported in PhpStorm: 7.1.3 (PS-133.982)
180 | https://github.com/idok/scss-lint-plugin/issues/5
181 | */
182 | if (severity.equals(HighlightSeverity.ERROR)) {
183 | return holder.createErrorAnnotation(range, message);
184 | }
185 | return holder.createWarningAnnotation(range, message);
186 | }
187 |
188 | public static Annotation createAnnotation(@NotNull AnnotationHolder holder, @NotNull HighlightSeverity severity, @Nullable TextAttributes forcedTextAttributes, @NotNull TextRange range, @NotNull String message) {
189 | if (forcedTextAttributes != null) {
190 | Annotation annotation = createAnnotation(holder, severity, range, message);
191 | annotation.setEnforcedTextAttributes(forcedTextAttributes);
192 | return annotation;
193 | }
194 | return createAnnotation(holder, severity, range, message);
195 | }
196 |
197 | @Nullable
198 | private static ScssLintAnnotationInput collectInformation(@NotNull PsiFile psiFile, @Nullable Editor editor) {
199 | if (psiFile.getContext() != null || !isScssFile(psiFile)) {
200 | return null;
201 | }
202 | VirtualFile virtualFile = psiFile.getVirtualFile();
203 | if (virtualFile == null || !virtualFile.isInLocalFileSystem()) {
204 | return null;
205 | }
206 | if (psiFile.getViewProvider() instanceof MultiplePsiFilesPerDocumentFileViewProvider) {
207 | return null;
208 | }
209 | Project project = psiFile.getProject();
210 | // ScssLintProjectComponent component = project.getComponent(ScssLintProjectComponent.class);
211 | // if (!component.isSettingsValid() || !component.isEnabled()) {
212 | // return new ScssLintAnnotationInput(project, psiFile, null, null, "Invalid settings!");
213 | // }
214 | Document document = PsiDocumentManager.getInstance(project).getDocument(psiFile);
215 | if (document == null) {
216 | return null;
217 | }
218 | String fileContent = document.getText();
219 | if (StringUtil.isEmptyOrSpaces(fileContent)) {
220 | return null;
221 | }
222 | EditorColorsScheme colorsScheme = editor == null ? null : editor.getColorsScheme();
223 | return new ScssLintAnnotationInput(project, psiFile, fileContent, colorsScheme);
224 | }
225 |
226 | private static boolean isScssFile(PsiFile file) {
227 | return file.getVirtualFile().getExtension().equals(SCSS);
228 | // return file instanceof SCSSFile && file.getFileType().equals(SCSSFileType.SCSS);
229 | }
230 |
231 | private static final Key TEMP_FILE = Key.create("SCSS_LINT_TEMP_FILE");
232 |
233 | private static void copyConfig(Project project, File temp) throws IOException {
234 | copyConfigFile(project, temp, ScssLintConfigFileChangeTracker.SCSS_LINT_YML);
235 | }
236 |
237 | private static void copyConfigFile(Project project, File temp, String fileName) throws IOException {
238 | VirtualFile jscs = project.getBaseDir().findChild(fileName);
239 | File tempJscs = new File(temp, fileName);
240 | if (jscs != null) {
241 | //check if stale?
242 | FileUtil.copy(new File(jscs.getPath()), tempJscs);
243 | tempJscs.deleteOnExit();
244 | }
245 | }
246 |
247 | @Nullable
248 | @Override
249 | public ScssLintAnnotationResult doAnnotate(ScssLintAnnotationInput collectedInfo) {
250 | BaseActualFile actualFile = null;
251 | try {
252 | PsiFile file = collectedInfo.psiFile;
253 | if (!isScssFile(file)) {
254 | return null;
255 | }
256 | ScssLintProjectComponent component = file.getProject().getComponent(ScssLintProjectComponent.class);
257 | if (!component.isEnabled()) {
258 | if (component.isDismissConfigurationHints()) {
259 | return null;
260 | }
261 | return new ScssLintAnnotationResult(collectedInfo, null, "SCSS Lint is available for this file but is not configured");
262 | }
263 | if (!component.isSettingsValid()) {
264 | return new ScssLintAnnotationResult(collectedInfo, null, "SCSS Lint is not configured correctly");
265 | }
266 |
267 | ScssLintConfigFileChangeTracker.getInstance(collectedInfo.project).startIfNeeded();
268 | actualFile = ActualFileManager.getOrCreateActualFile(TEMP_FILE, file, collectedInfo.fileContent);
269 | if (actualFile instanceof TempFile) {
270 | copyConfig(file.getProject(), new File(actualFile.getCwd()));
271 | }
272 | if (actualFile == null) {
273 | LOG.warn("Failed to create file for lint");
274 | return null;
275 | }
276 | LintResult result = ScssLintRunner.runLint(actualFile.getCwd(), actualFile.getPath(), component.scssLintExecutable, component.scssLintConfigFile);
277 |
278 | if (StringUtils.isNotEmpty(result.errorOutput)) {
279 | component.showInfoNotification(result.errorOutput, NotificationType.WARNING);
280 | return null;
281 | }
282 | Document document = PsiDocumentManager.getInstance(file.getProject()).getDocument(file);
283 | if (document == null) {
284 | component.showInfoNotification("Error running SCSS Lint inspection: Could not get document for file " + file.getName(), NotificationType.WARNING);
285 | LOG.warn("Could not get document for file " + file.getName());
286 | return null;
287 | }
288 | return new ScssLintAnnotationResult(collectedInfo, result);
289 | } catch (Exception e) {
290 | LOG.error("Error running ScssLint inspection: ", e);
291 | ScssLintProjectComponent.showNotification("Error running SCSS Lint inspection: " + e.getMessage(), NotificationType.ERROR);
292 | } finally {
293 | ActualFileManager.dispose(actualFile);
294 | }
295 | return null;
296 | }
297 | }
298 |
299 | class ScssLintAnnotationInput {
300 | public final String fileContent;
301 | public final EditorColorsScheme colorsScheme;
302 | public final Project project;
303 | public final PsiFile psiFile;
304 |
305 | public ScssLintAnnotationInput(Project project, PsiFile psiFile, String fileContent, EditorColorsScheme colorsScheme) {
306 | this.project = project;
307 | this.psiFile = psiFile;
308 | this.fileContent = fileContent;
309 | this.colorsScheme = colorsScheme;
310 | }
311 | }
312 |
313 | class ScssLintAnnotationResult {
314 | public ScssLintAnnotationResult(ScssLintAnnotationInput input, LintResult result) {
315 | this.input = input;
316 | this.result = result;
317 | }
318 |
319 | public ScssLintAnnotationResult(ScssLintAnnotationInput input, LintResult result, String fileLevel) {
320 | this.input = input;
321 | this.result = result;
322 | this.fileLevel = fileLevel;
323 | }
324 |
325 | public final ScssLintAnnotationInput input;
326 | public final LintResult result;
327 | public String fileLevel;
328 | }
329 |
--------------------------------------------------------------------------------
/scss-lint-plugin/src/main/java/com/scss/ScssLintInspection.java:
--------------------------------------------------------------------------------
1 | package com.scss;
2 |
3 | import com.google.common.base.Joiner;
4 | import com.intellij.codeInspection.*;
5 | import com.intellij.codeInspection.ex.UnfairLocalInspectionTool;
6 | import com.intellij.ide.DataManager;
7 | import com.intellij.openapi.actionSystem.CommonDataKeys;
8 | import com.intellij.openapi.actionSystem.DataContext;
9 | import com.intellij.openapi.diagnostic.Logger;
10 | //import com.intellij.openapi.options.Configurable;
11 | //import com.intellij.openapi.options.ex.Settings;
12 | //import com.intellij.openapi.options.newEditor.OptionsEditor;
13 | //import com.intellij.openapi.options.newEditor.OptionsEditorContext;
14 | import com.intellij.openapi.project.Project;
15 | import com.intellij.openapi.util.Key;
16 | import com.intellij.psi.PsiElement;
17 | import com.intellij.psi.PsiElementVisitor;
18 | import com.intellij.psi.PsiFile;
19 | import com.intellij.ui.HyperlinkAdapter;
20 | import com.intellij.ui.HyperlinkLabel;
21 | import com.intellij.ui.IdeBorderFactory;
22 | import com.intellij.util.containers.ContainerUtil;
23 | import com.scss.settings.ScssLintSettingsPage;
24 | import org.jetbrains.annotations.NotNull;
25 | import org.jetbrains.annotations.Nullable;
26 |
27 | import javax.swing.*;
28 | import javax.swing.event.HyperlinkEvent;
29 | import java.awt.*;
30 | import java.util.List;
31 |
32 | //import org.jetbrains.plugins.sass.SASSBundle;
33 |
34 | public class ScssLintInspection extends LocalInspectionTool implements BatchSuppressableTool, UnfairLocalInspectionTool { //extends PropertySuppressableInspectionBase {
35 |
36 | private static final String INSPECTION_SHORT_NAME = "ScssLintInspection";
37 | public static final Key KEY = Key.create(INSPECTION_SHORT_NAME);
38 |
39 | private static final Logger LOG = Logger.getInstance(ScssLintBundle.LOG_ID);
40 |
41 | @NotNull
42 | public String getDisplayName() {
43 | return ScssLintBundle.message("scss.property.inspection.display.name");
44 | }
45 |
46 | @NotNull
47 | public String getShortName() {
48 | return INSPECTION_SHORT_NAME;
49 | }
50 |
51 |
52 | public ProblemDescriptor[] checkFile(@NotNull PsiFile file, @NotNull final InspectionManager manager, final boolean isOnTheFly) {
53 | return ExternalAnnotatorInspectionVisitor.checkFileWithExternalAnnotator(file, manager, isOnTheFly, new ScssLintExternalAnnotator());
54 | }
55 |
56 | @NotNull
57 | @Override
58 | public PsiElementVisitor buildVisitor(@NotNull ProblemsHolder holder, boolean isOnTheFly, @NotNull LocalInspectionToolSession session) {
59 | return new ExternalAnnotatorInspectionVisitor(holder, new ScssLintExternalAnnotator(), isOnTheFly);
60 | }
61 |
62 | public JComponent createOptionsPanel() {
63 | JPanel panel = new JPanel(new FlowLayout(FlowLayout.LEFT));
64 | HyperlinkLabel settingsLink = createHyperLink();
65 | panel.setBorder(IdeBorderFactory.createTitledBorder(getDisplayName() + " options"));
66 | panel.add(settingsLink);
67 | return panel;
68 | }
69 |
70 | @NotNull
71 | public String getId() {
72 | return "Settings.JavaScript.Linters.ScssLint";
73 | }
74 |
75 | @NotNull
76 | private HyperlinkLabel createHyperLink() {
77 | // List path = ContainerUtil.newArrayList(JSBundle.message("settings.javascript.root.configurable.name"), JSBundle.message("settings.javascript.linters.configurable.name"), getDisplayName());
78 | List path = ContainerUtil.newArrayList(ScssLintBundle.message("scss.inspections.group.name"), ScssLintBundle.message("scss.inspection.group.name"), getDisplayName());
79 | String title = Joiner.on(" / ").join(path);
80 | final HyperlinkLabel settingsLink = new HyperlinkLabel(title);
81 | settingsLink.addHyperlinkListener(new HyperlinkAdapter() {
82 | public void hyperlinkActivated(HyperlinkEvent e) {
83 | DataContext dataContext = DataManager.getInstance().getDataContext(settingsLink);
84 | Project project = CommonDataKeys.PROJECT.getData(dataContext);
85 | if (project != null) {
86 | showSettings(project);
87 | // } else {
88 | // new ScssLintSettingsPage(null).showSettings();
89 | }
90 |
91 | // Settings settings = (Settings) Settings.KEY.getData(dataContext);
92 | // if (settings == null) {
93 | // configurable.showEditDialog();
94 | // } else {
95 | // settings.select(settings.find(getId()));
96 | // }
97 | //
98 | // OptionsEditor optionsEditor = OptionsEditor.KEY.getData(dataContext);
99 | // if (optionsEditor == null) {
100 | // Project project = CommonDataKeys.PROJECT.getData(dataContext);
101 | // if (project != null) {
102 | // showSettings(project);
103 | // }
104 | // return;
105 | // }
106 | // Configurable configurable = optionsEditor.findConfigurableById(ScssLintInspection.this.getId());
107 | // if (configurable != null) {
108 | // optionsEditor.clearSearchAndSelect(configurable);
109 | // }
110 | //
111 | //
112 | //
113 | // Project project = CommonDataKeys.PROJECT.getData(dataContext);
114 | // if(project == null) {
115 | // LOG.warn("No project found in data context");
116 | // } else {
117 | // JSLinterConfigurable configurable = JSLinterInspection.this.getExternalAnnotatorForBatchInspection().createSettingsConfigurable(project);
118 | // Settings settings = (Settings)Settings.KEY.getData(dataContext);
119 | // if(settings == null) {
120 | // configurable.showEditDialog();
121 | // } else {
122 | // settings.select(settings.find(configurable.getId()));
123 | // }
124 | // }
125 | }
126 | });
127 | return settingsLink;
128 | }
129 |
130 | static void showSettings(Project project) {
131 | ScssLintSettingsPage configurable = new ScssLintSettingsPage(project);
132 | configurable.showSettings();
133 | // String dimensionKey = ShowSettingsUtilImpl.createDimensionKey(configurable);
134 | // SingleConfigurableEditor singleConfigurableEditor = new SingleConfigurableEditor(project, configurable, dimensionKey, false);
135 | // singleConfigurableEditor.show();
136 | }
137 |
138 | @Override
139 | public boolean isSuppressedFor(@NotNull PsiElement element) {
140 | return false;
141 | }
142 |
143 | @NotNull
144 | @Override
145 | public SuppressQuickFix[] getBatchSuppressActions(@Nullable PsiElement element) {
146 | return new SuppressQuickFix[0];
147 | }
148 | }
--------------------------------------------------------------------------------
/scss-lint-plugin/src/main/java/com/scss/ScssLintProjectComponent.java:
--------------------------------------------------------------------------------
1 | package com.scss;
2 |
3 | import com.intellij.notification.Notification;
4 | import com.intellij.notification.NotificationListener;
5 | import com.intellij.notification.NotificationType;
6 | import com.intellij.notification.Notifications;
7 | import com.intellij.openapi.components.ProjectComponent;
8 | import com.intellij.openapi.diagnostic.Logger;
9 | import com.intellij.openapi.project.Project;
10 | import com.scss.settings.Settings;
11 | import com.wix.utils.FileUtils;
12 | import com.wix.utils.FileUtils.ValidationStatus;
13 | import org.jetbrains.annotations.NotNull;
14 |
15 | public class ScssLintProjectComponent implements ProjectComponent {
16 | public static final String FIX_CONFIG_HREF = "\nFix Configuration";
17 | protected final Project project;
18 | protected Settings settings;
19 | protected boolean settingValidStatus;
20 | protected String settingValidVersion;
21 | protected String settingVersionLastShowNotification;
22 |
23 | private static final Logger LOG = Logger.getInstance(ScssLintBundle.LOG_ID);
24 |
25 | public String scssLintConfigFile;
26 | public String scssLintExecutable;
27 | public boolean treatAsWarnings;
28 | public boolean pluginEnabled;
29 | public boolean dismissConfigurationHints;
30 |
31 | public static final String PLUGIN_NAME = "SCSS Lint";
32 |
33 | public ScssLintProjectComponent(Project project) {
34 | this.project = project;
35 | settings = Settings.getInstance(project);
36 | }
37 |
38 | @Override
39 | public void projectOpened() {
40 | if (isEnabled()) {
41 | isSettingsValid();
42 | }
43 | }
44 |
45 | @Override
46 | public void projectClosed() {
47 | }
48 |
49 | @Override
50 | public void initComponent() {
51 | if (isEnabled()) {
52 | isSettingsValid();
53 | }
54 | }
55 |
56 | @Override
57 | public void disposeComponent() {
58 | }
59 |
60 | @NotNull
61 | @Override
62 | public String getComponentName() {
63 | return ScssLintProjectComponent.class.getName();
64 | }
65 |
66 | public boolean isEnabled() {
67 | return Settings.getInstance(project).pluginEnabled;
68 | }
69 |
70 | public boolean isDismissConfigurationHints() {
71 | return Settings.getInstance(project).dismissConfigurationHints;
72 | }
73 |
74 | public boolean isSettingsValid() {
75 | if (!settings.getVersion().equals(settingValidVersion)) {
76 | validateSettings();
77 | settingValidVersion = settings.getVersion();
78 | }
79 | return settingValidStatus;
80 | }
81 |
82 | public void validateSettings() {
83 | settingValidStatus = isValid();
84 | if (!settingValidStatus) {
85 | return;
86 | }
87 |
88 | // if (StringUtil.isNotEmpty(settings.scssLintExecutable)) {
89 | // File file = new File(project.getBasePath(), settings.scssLintExecutable);
90 | // if (!file.exists()) {
91 | // showErrorConfigNotification(ESLintBundle.message("eslint.rules.dir.does.not.exist", file.toString()));
92 | // LOG.debug("Rules directory not found");
93 | // settingValidStatus = false;
94 | // return false;
95 | // }
96 | // }
97 | scssLintExecutable = settings.scssLintExecutable;
98 | scssLintConfigFile = settings.scssLintConfigFile;
99 | treatAsWarnings = settings.treatAllIssuesAsWarnings;
100 | pluginEnabled = settings.pluginEnabled;
101 | dismissConfigurationHints = settings.dismissConfigurationHints;
102 | }
103 |
104 | public boolean isValid() {
105 | // do not validate if disabled
106 | if (!settings.pluginEnabled) {
107 | return true;
108 | }
109 | // boolean status = validateField("Node Interpreter", settings.nodeInterpreter, true, false, true);
110 | // if (!status) {
111 | // return false;
112 | // }
113 | // status = validateField("Rules", settings.rulesPath, false, true, false);
114 | // if (!status) {
115 | // return false;
116 | // }
117 | boolean status = validateField("SCSS Lint bin", settings.scssLintExecutable, false, false, true);
118 | if (!status) {
119 | return false;
120 | }
121 | return true;
122 | }
123 |
124 | private boolean validateField(String fieldName, String value, boolean shouldBeAbsolute, boolean allowEmpty, boolean isFile) {
125 | ValidationStatus r = FileUtils.validateProjectPath(shouldBeAbsolute ? null : project, value, allowEmpty, isFile);
126 | if (r == ValidationStatus.IS_EMPTY && !allowEmpty) {
127 | String msg = ScssLintBundle.message("scss.path.is.empty", fieldName);
128 | validationFailed(msg);
129 | return false;
130 | }
131 | if (isFile) {
132 | if (r == ValidationStatus.NOT_A_FILE) {
133 | String msg = ScssLintBundle.message("scss.file.is.not.a.file", fieldName, value);
134 | validationFailed(msg);
135 | return false;
136 | }
137 | } else {
138 | if (r == ValidationStatus.NOT_A_DIRECTORY) {
139 | String msg = ScssLintBundle.message("scss.directory.is.not.a.dir", fieldName, value);
140 | validationFailed(msg);
141 | return false;
142 | }
143 | }
144 | if (r == ValidationStatus.DOES_NOT_EXIST) {
145 | String msg = ScssLintBundle.message("scss.file.does.not.exist", fieldName, value);
146 | validationFailed(msg);
147 | return false;
148 | }
149 | return true;
150 | }
151 |
152 | private void validationFailed(String msg) {
153 | NotificationListener notificationListener = (notification, event) -> ScssLintInspection.showSettings(project);
154 | String errorMessage = msg + FIX_CONFIG_HREF;
155 | showInfoNotification(errorMessage, NotificationType.WARNING, notificationListener);
156 | LOG.debug(msg);
157 | settingValidStatus = false;
158 | }
159 |
160 | protected void showErrorConfigNotification(String content) {
161 | if (!settings.getVersion().equals(settingVersionLastShowNotification)) {
162 | settingVersionLastShowNotification = settings.getVersion();
163 | showInfoNotification(content, NotificationType.WARNING);
164 | }
165 | }
166 |
167 | public void showInfoNotification(String content, NotificationType type) {
168 | Notification errorNotification = new Notification(PLUGIN_NAME, PLUGIN_NAME, content, type);
169 | Notifications.Bus.notify(errorNotification, this.project);
170 | }
171 |
172 | public void showInfoNotification(String content, NotificationType type, NotificationListener notificationListener) {
173 | Notification errorNotification = new Notification(PLUGIN_NAME, PLUGIN_NAME, content, type, notificationListener);
174 | Notifications.Bus.notify(errorNotification, this.project);
175 | }
176 |
177 | public static void showNotification(String content, NotificationType type) {
178 | Notification errorNotification = new Notification(PLUGIN_NAME, PLUGIN_NAME, content, type);
179 | Notifications.Bus.notify(errorNotification);
180 | }
181 | }
182 |
--------------------------------------------------------------------------------
/scss-lint-plugin/src/main/java/com/scss/ThreadLocalActualFile.java:
--------------------------------------------------------------------------------
1 | //package com.scss;
2 | //
3 | //import com.intellij.openapi.diagnostic.Logger;
4 | //import com.intellij.openapi.util.io.FileUtil;
5 | //import com.intellij.openapi.vfs.VirtualFile;
6 | //import com.wix.utils.FileUtils;
7 | //import org.jetbrains.annotations.NotNull;
8 | //import org.jetbrains.annotations.Nullable;
9 | //
10 | //import java.io.File;
11 | //import java.io.IOException;
12 | //
13 | ///**
14 | // * Lint target file thread local storage
15 | // */
16 | //class ThreadLocalActualFile extends ThreadLocal {
17 | // private final String baseName;
18 | // private final String extension;
19 | // private final VirtualFile file;
20 | // private static final Logger LOG = Logger.getInstance(ScssLintBundle.LOG_ID);
21 | //
22 | // public boolean isTemp;
23 | //
24 | // private static final String SCSS_LINT_TMP = "_scsslint_tmp";
25 | // private static final String TEMP_DIR_NAME = "intellij-scsslint-temp";
26 | //
27 | // ThreadLocalActualFile(@NotNull VirtualFile file) {
28 | // this.baseName = file.getNameWithoutExtension();
29 | // this.extension = FileUtils.getExtensionWithDot(file);
30 | // this.file = file;
31 | // }
32 | //
33 | // @Nullable
34 | // public File getOrCreateFile() {
35 | // String path = super.get();
36 | // if (path != null) {
37 | // File file = new File(path);
38 | // if (file.isFile()) {
39 | // return file;
40 | // }
41 | // }
42 | // File file = createFile();
43 | // if (file != null) {
44 | // set(file.getAbsolutePath());
45 | // return file;
46 | // }
47 | // return null;
48 | // }
49 | //
50 | // @Nullable
51 | // public static File getOrCreateTempDir() {
52 | // File tmpDir = new File(FileUtil.getTempDirectory());
53 | // File dir = new File(tmpDir, TEMP_DIR_NAME);
54 | // if (dir.isDirectory() || dir.mkdirs()) {
55 | // return dir;
56 | // }
57 | // try {
58 | // return FileUtil.createTempDirectory(tmpDir, TEMP_DIR_NAME, null);
59 | // } catch (IOException ignored) {
60 | // LOG.warn("Can't create '" + TEMP_DIR_NAME + "' temporary directory.");
61 | // }
62 | // return null;
63 | // }
64 | //
65 | // @Nullable
66 | // private File createFile() {
67 | //// File retFile = new File(file.getParent().getPath(), file.getNameWithoutExtension() + "_eslint_tmp." + file.getExtension());
68 | // File retFile;
69 | // try {
70 | // // try to create a temp file next to original file
71 | // retFile = File.createTempFile(this.baseName + SCSS_LINT_TMP, this.extension, new File(file.getParent().getPath()));
72 | // isTemp = true;
73 | // return retFile;
74 | // } catch (IOException e) {
75 | // LOG.warn("Can not create temp file", e);
76 | // }
77 | //
78 | // // try to create a temp file in temp folder
79 | // File dir = getOrCreateTempDir();
80 | // if (dir == null) {
81 | // return null;
82 | // }
83 | // File file = new File(dir, this.baseName + this.extension);
84 | // boolean created = false;
85 | // if (!file.exists()) {
86 | // try {
87 | // created = file.createNewFile();
88 | // } catch (IOException ignored) {
89 | // LOG.warn("Can not create " + file.getAbsolutePath());
90 | // }
91 | // }
92 | // if (!created) {
93 | // try {
94 | // file = FileUtil.createTempFile(dir, this.baseName, this.extension);
95 | // } catch (IOException e) {
96 | // LOG.warn("Can not create temp file", e);
97 | // return null;
98 | // }
99 | // }
100 | // file.deleteOnExit();
101 | // return file;
102 | // }
103 | //}
104 |
--------------------------------------------------------------------------------
/scss-lint-plugin/src/main/java/com/scss/annotator/BaseActionFix.java:
--------------------------------------------------------------------------------
1 | package com.scss.annotator;
2 |
3 | import com.intellij.codeInsight.intention.HighPriorityAction;
4 | import com.intellij.codeInsight.intention.IntentionAction;
5 | import com.intellij.codeInspection.LocalQuickFixAndIntentionActionOnPsiElement;
6 | import com.intellij.openapi.editor.Editor;
7 | import com.intellij.openapi.project.Project;
8 | import com.intellij.psi.PsiElement;
9 | import com.intellij.psi.PsiFile;
10 | import org.jetbrains.annotations.NotNull;
11 | import org.jetbrains.annotations.Nullable;
12 |
13 | /**
14 | * @author idok
15 | */
16 | public abstract class BaseActionFix extends LocalQuickFixAndIntentionActionOnPsiElement implements IntentionAction, HighPriorityAction {
17 | public BaseActionFix(PsiElement element) {
18 | super(element);
19 | }
20 |
21 | @NotNull
22 | @Override
23 | public String getFamilyName() {
24 | return getText();
25 | }
26 |
27 | protected abstract void fix(@NotNull Project project, Editor editor, PsiFile file, PsiElement start);
28 |
29 | public void invoke(@NotNull Project project, @NotNull PsiFile file, @Nullable("is null when called from inspection") Editor editor, @NotNull PsiElement start, @NotNull PsiElement end) {
30 | fix(project, editor, file, start);
31 | }
32 |
33 | @Override
34 | public boolean startInWriteAction() {
35 | return true;
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/scss-lint-plugin/src/main/java/com/scss/annotator/Fixes.java:
--------------------------------------------------------------------------------
1 | package com.scss.annotator;
2 |
3 | import com.intellij.psi.PsiElement;
4 | import org.jetbrains.annotations.Nullable;
5 |
6 | public final class Fixes {
7 | private Fixes() {
8 | }
9 |
10 | @Nullable
11 | public static BaseActionFix getFixForRule(String rule, PsiElement element) {
12 | if ("PropertySortOrder".equals(rule)) {
13 | return new PropertySortOrderFix(element);
14 | }
15 | return null;
16 | }
17 | }
--------------------------------------------------------------------------------
/scss-lint-plugin/src/main/java/com/scss/annotator/PropertySortOrderFix.java:
--------------------------------------------------------------------------------
1 | //package com.scss.annotator;
2 | //
3 | //import com.intellij.openapi.editor.Editor;
4 | //import com.intellij.openapi.project.Project;
5 | //import com.intellij.psi.PsiElement;
6 | //import com.intellij.psi.PsiFile;
7 | //import com.intellij.psi.css.CssBlock;
8 | //import com.intellij.psi.css.CssDeclaration;
9 | //import com.intellij.psi.css.impl.parsing.CssParser;
10 | //import com.intellij.psi.css.impl.util.table.CssPropertyUtil;
11 | //import com.intellij.psi.util.PsiTreeUtil;
12 | //import com.intellij.util.IncorrectOperationException;
13 | //import com.intellij.util.containers.ContainerUtil;
14 | //import com.scss.ScssLintBundle;
15 | //import org.jetbrains.annotations.NotNull;
16 | //
17 | //import java.util.Comparator;
18 | //import java.util.regex.Matcher;
19 | //import java.util.regex.Pattern;
20 | //
21 | ///**
22 | // * @author idok
23 | // */
24 | //public class PropertySortOrderFix extends BaseActionFix {
25 | //
26 | // private static final String[] VENDOR_PREFIXS = {
27 | // "-moz-" /* Firefox and other browsers using Mozilla's browser engine */,
28 | // "-webkit-" /* Safari, Chrome and browsers using the Webkit engine */,
29 | // "-o-" /* Opera */,
30 | // "-ms-" /* Internet Explorer (but not always) */};
31 | //
32 | // private static final Pattern COMPILE = Pattern.compile("-(?:moz|o|webkit|ms)-(font)");
33 | //
34 | // public PropertySortOrderFix(PsiElement element) {
35 | // super(element);
36 | // }
37 | //
38 | // @NotNull
39 | // @Override
40 | // public String getText() {
41 | // return ScssLintBundle.message("inspection.fix.sort");
42 | // }
43 | //
44 | // public static String strip(String p) {
45 | // Matcher m = COMPILE.matcher(p);
46 | // return m.matches() ? m.group(1) : p;
47 | // }
48 | //
49 | // @Override
50 | // public void fix(@NotNull Project project, Editor editor, PsiFile file, PsiElement start) throws IncorrectOperationException {
51 | // CssBlock block = PsiTreeUtil.getParentOfType(start, CssBlock.class);
52 | // CssDeclaration[] declarations = block.getDeclarations();
53 | // CssDeclaration[] sorted = new CssDeclaration[declarations.length];
54 | // for (int i = 0; i < sorted.length; i++) {
55 | // sorted[i] = (CssDeclaration) declarations[i].copy();
56 | // }
57 | //
58 | // ContainerUtil.sort(sorted, (cssDeclaration, cssDeclaration2) -> {
59 | // String p1 = CssPropertyUtil.getElementNameWithoutVendorPrefix(cssDeclaration.getPropertyName());
60 | // String v1 = CssPropertyUtil.getVendorPrefix(cssDeclaration.getPropertyName());
61 | // String p2 = CssPropertyUtil.getElementNameWithoutVendorPrefix(cssDeclaration2.getPropertyName());
62 | // String v2 = CssPropertyUtil.getVendorPrefix(cssDeclaration2.getPropertyName());
63 | // return p1.compareTo(p2);
64 | // });
65 | //
66 | // for (int i = 0; i < declarations.length; i++) {
67 | // declarations[i].replace(sorted[i]);
68 | // }
69 | // }
70 | //}
71 |
--------------------------------------------------------------------------------
/scss-lint-plugin/src/main/java/com/scss/annotator/SortProperty.kt:
--------------------------------------------------------------------------------
1 | //package com.scss.annotator
2 | //
3 | //import com.intellij.openapi.editor.Editor
4 | //import com.intellij.openapi.project.Project
5 | //import com.intellij.psi.PsiElement
6 | //import com.intellij.psi.PsiFile
7 | //import com.intellij.psi.css.CssBlock
8 | //import com.intellij.psi.css.CssDeclaration
9 | ////import com.intellij.psi.css.impl.util.table.CssDescriptorsUtil //CssPropertyUtil
10 | //import com.intellij.psi.util.PsiTreeUtil
11 | //import com.intellij.util.IncorrectOperationException
12 | //import com.scss.ScssLintBundle
13 | //import java.util.*
14 | //import java.util.regex.Pattern
15 | //
16 | ///**
17 | // * @author idok
18 | // */
19 | //class PropertySortOrderFix(element: PsiElement) : BaseActionFix(element) {
20 | //
21 | // override fun getText(): String {
22 | // return ScssLintBundle.message("inspection.fix.sort")
23 | // }
24 | //
25 | // @Throws(IncorrectOperationException::class)
26 | // public override fun fix(project: Project, editor: Editor, file: PsiFile, start: PsiElement) {
27 | // val block = PsiTreeUtil.getParentOfType(start, CssBlock::class.java) ?: return
28 | // val declarations = block.declarations
29 | // val cloned:List = declarations.map { it.copy() as CssDeclaration }
30 | // val sorted = cloned.sortedWith(CssDeclarationComparator())
31 | // for (i in declarations.indices) {
32 | // declarations[i].replace(sorted[i])
33 | // }
34 | // }
35 | //
36 | // companion object {
37 | // private val COMPILE = Pattern.compile("-(?:moz|o|webkit|ms)-(font)")
38 | //
39 | // fun strip(p: String): String {
40 | // val m = COMPILE.matcher(p)
41 | // return if (m.matches()) m.group(1) else p
42 | // }
43 | //
44 | // fun parse(it: CssDeclaration?) = parse(it?.propertyName ?: "")
45 | //// fun parse(it: String) = CP2(CssPropertyUtil.getVendorPrefix(it), CssPropertyUtil.getElementNameWithoutVendorPrefix(it))
46 | // fun parse(it: String) = CP2("", "")
47 | // }
48 | //
49 | // class CssDeclarationComparator : Comparator {
50 | // override fun compare(o1: CssDeclaration?, o2: CssDeclaration?): Int {
51 | // val p1 = parse(o1)
52 | // val p2 = parse(o2)
53 | // return p1.compareTo(p2)
54 | // }
55 | // }
56 | //
57 | // data class CP2(val prefix: String, val name: String) {
58 | // override fun toString() = "$prefix$name"
59 | //
60 | // fun compareTo(o1: CP2): Int {
61 | // return name.compareTo(o1.name)
62 | // }
63 | // }
64 | //}
65 | //
66 | //
67 |
--------------------------------------------------------------------------------
/scss-lint-plugin/src/main/java/com/scss/config/ScssLintConfigFileChangeTracker.java:
--------------------------------------------------------------------------------
1 | package com.scss.config;
2 |
3 | import com.intellij.codeInsight.daemon.DaemonCodeAnalyzer;
4 | import com.intellij.openapi.application.ApplicationManager;
5 | import com.intellij.openapi.components.ServiceManager;
6 | import com.intellij.openapi.editor.EditorFactory;
7 | import com.intellij.openapi.editor.event.DocumentEvent;
8 | import com.intellij.openapi.editor.event.DocumentListener;
9 | import com.intellij.openapi.editor.event.EditorEventMulticaster;
10 | import com.intellij.openapi.fileEditor.FileDocumentManager;
11 | import com.intellij.openapi.project.Project;
12 | import com.intellij.openapi.vfs.*;
13 | import com.scss.ScssLintProjectComponent;
14 | import com.scss.utils.ScssLintFinder;
15 | import org.jetbrains.annotations.Contract;
16 | import org.jetbrains.annotations.NotNull;
17 |
18 | import java.util.concurrent.atomic.AtomicBoolean;
19 |
20 | public class ScssLintConfigFileChangeTracker {
21 | private final AtomicBoolean TRACKING = new AtomicBoolean(false);
22 | private final Project project;
23 |
24 | public static final String SCSS_LINT_YML = "." + ScssLintFinder.SCSS_LINT_YML;
25 |
26 | public ScssLintConfigFileChangeTracker(@NotNull Project project) {
27 | this.project = project;
28 | }
29 |
30 | @NotNull
31 | public static ScssLintConfigFileChangeTracker getInstance(@NotNull Project project) {
32 | return ServiceManager.getService(project, ScssLintConfigFileChangeTracker.class);
33 | }
34 |
35 | public void startIfNeeded() {
36 | if (TRACKING.compareAndSet(false, true))
37 | ApplicationManager.getApplication().invokeLater(new Runnable() {
38 | public void run() {
39 | ApplicationManager.getApplication().runWriteAction(new Runnable() {
40 | public void run() {
41 | VirtualFileManager.getInstance().addVirtualFileListener(new ScssLintConfigFileVfsListener(), ScssLintConfigFileChangeTracker.this.project);
42 | EditorEventMulticaster multicaster = EditorFactory.getInstance().getEventMulticaster();
43 | multicaster.addDocumentListener(new ScssLintConfigFileDocumentListener(), ScssLintConfigFileChangeTracker.this.project);
44 | }
45 | });
46 | }
47 | });
48 | }
49 |
50 | private void onChange(@NotNull VirtualFile file) {
51 | // if (file.getFileType().equals(ScssLintConfigFileType.INSTANCE) && !project.isDisposed()) {
52 | if (SCSS_LINT_YML.equals(file.getName()) && !project.isDisposed()) {
53 | restartCodeAnalyzerIfNeeded();
54 | }
55 | }
56 |
57 | private void restartCodeAnalyzerIfNeeded() {
58 | ScssLintProjectComponent component = project.getComponent(ScssLintProjectComponent.class);
59 | if (component.isEnabled()) {
60 | DaemonCodeAnalyzer.getInstance(project).restart();
61 | }
62 | }
63 |
64 | private final class ScssLintConfigFileDocumentListener implements DocumentListener {
65 | private ScssLintConfigFileDocumentListener() {
66 | }
67 |
68 | public void beforeDocumentChange(@NotNull DocumentEvent event) {
69 | }
70 |
71 | public void documentChanged(@NotNull DocumentEvent event) {
72 | VirtualFile file = FileDocumentManager.getInstance().getFile(event.getDocument());
73 | if (file != null) {
74 | ScssLintConfigFileChangeTracker.this.onChange(file);
75 | }
76 | }
77 | }
78 |
79 | private final class ScssLintConfigFileVfsListener implements VirtualFileListener {
80 | @Contract(pure = true)
81 | private ScssLintConfigFileVfsListener() {
82 | }
83 |
84 | public void fileCreated(@NotNull VirtualFileEvent event) {
85 | ScssLintConfigFileChangeTracker.this.onChange(event.getFile());
86 | }
87 |
88 | public void fileDeleted(@NotNull VirtualFileEvent event) {
89 | ScssLintConfigFileChangeTracker.this.onChange(event.getFile());
90 | }
91 |
92 | public void fileMoved(@NotNull VirtualFileMoveEvent event) {
93 | ScssLintConfigFileChangeTracker.this.onChange(event.getFile());
94 | }
95 |
96 | public void fileCopied(@NotNull VirtualFileCopyEvent event) {
97 | ScssLintConfigFileChangeTracker.this.onChange(event.getFile());
98 | ScssLintConfigFileChangeTracker.this.onChange(event.getOriginalFile());
99 | }
100 | }
101 | }
102 |
103 |
--------------------------------------------------------------------------------
/scss-lint-plugin/src/main/java/com/scss/config/ScssLintConfigFileType.java:
--------------------------------------------------------------------------------
1 | //package com.scss.config;
2 | //
3 | //import com.intellij.openapi.fileTypes.LanguageFileType;
4 | //import icons.ScssLintIcons;
5 | //import org.jetbrains.annotations.NotNull;
6 | //import org.jetbrains.yaml.YAMLLanguage;
7 | //
8 | //import javax.swing.*;
9 | //
10 | //public class ScssLintConfigFileType extends LanguageFileType {
11 | // public static final ScssLintConfigFileType INSTANCE = new ScssLintConfigFileType();
12 | // public static final String SCSS_LINT_YML = "scss-lint.yml";
13 | // public static final String SCSS_LINT_YML_NAME = "." + SCSS_LINT_YML;
14 | // public static final String SCSS_LINT_YAML_NAME = ".scss-lint.yaml";
15 | //
16 | // public static boolean isScssConfigFile(String name) {
17 | // return name.equals(SCSS_LINT_YML_NAME) || name.equals(SCSS_LINT_YAML_NAME);
18 | // }
19 | //
20 | // private ScssLintConfigFileType() {
21 | // super(YAMLLanguage.INSTANCE);
22 | // }
23 | //
24 | // @NotNull
25 | // public String getName() {
26 | // return "SCSS Lint";
27 | // }
28 | //
29 | // @NotNull
30 | // public String getDescription() {
31 | // return "SCSS Lint configuration file";
32 | // }
33 | //
34 | // @NotNull
35 | // public String getDefaultExtension() {
36 | // return SCSS_LINT_YML;
37 | // }
38 | //
39 | // @NotNull
40 | // public Icon getIcon() {
41 | // return ScssLintIcons.ESLint;
42 | // }
43 | //}
--------------------------------------------------------------------------------
/scss-lint-plugin/src/main/java/com/scss/config/ScssLintConfigFileTypeFactory.java:
--------------------------------------------------------------------------------
1 | //package com.scss.config;
2 | //
3 | //import com.intellij.openapi.fileTypes.ExactFileNameMatcher;
4 | //import com.intellij.openapi.fileTypes.ExtensionFileNameMatcher;
5 | //import com.intellij.openapi.fileTypes.FileTypeConsumer;
6 | //import com.intellij.openapi.fileTypes.FileTypeFactory;
7 | //import org.jetbrains.annotations.NotNull;
8 | //
9 | //public class ScssLintConfigFileTypeFactory extends FileTypeFactory {
10 | // public void createFileTypes(@NotNull FileTypeConsumer consumer) {
11 | // consumer.consume(ScssLintConfigFileType.INSTANCE,
12 | // new ExactFileNameMatcher(ScssLintConfigFileType.SCSS_LINT_YML_NAME),
13 | // new ExactFileNameMatcher(ScssLintConfigFileType.SCSS_LINT_YAML_NAME));
14 | //// consumer.consume(ScssLintConfigFileType.INSTANCE, new ExtensionFileNameMatcher(ScssLintConfigFileType.SCSS_LINT_YML));
15 | // //, new ExactFileNameMatcher("eslint.json")
16 | // }
17 | //}
--------------------------------------------------------------------------------
/scss-lint-plugin/src/main/java/com/scss/config/ScssLintConfigFileUtil.java:
--------------------------------------------------------------------------------
1 | //package com.scss.config;
2 | //
3 | //import com.intellij.openapi.vfs.VirtualFile;
4 | //import com.intellij.psi.PsiElement;
5 | //import com.intellij.psi.PsiFile;
6 | //
7 | ///**
8 | // * @author idok
9 | // */
10 | //public final class ScssLintConfigFileUtil {
11 | // private ScssLintConfigFileUtil() {
12 | // }
13 | //
14 | // public static boolean isScssLintConfigFile(PsiFile file) {
15 | // return file != null && (isScssLintConfigFile(file.getVirtualFile()) || file.getFileType().equals(ScssLintConfigFileType.INSTANCE));
16 | // }
17 | //
18 | // public static boolean isScssLintConfigFile(PsiElement position) {
19 | // return isScssLintConfigFile(position.getContainingFile().getOriginalFile().getVirtualFile());
20 | // }
21 | //
22 | // public static boolean isScssLintConfigFile(VirtualFile file) {
23 | // return file != null && file.getExtension() != null &&
24 | // file.getExtension().equals(ScssLintConfigFileType.SCSS_LINT_YML);
25 | // }
26 | //
27 | //}
28 |
--------------------------------------------------------------------------------
/scss-lint-plugin/src/main/java/com/scss/settings/ScssLintSettingsPage.form:
--------------------------------------------------------------------------------
1 |
2 |
146 |
--------------------------------------------------------------------------------
/scss-lint-plugin/src/main/java/com/scss/settings/ScssLintSettingsPage.java:
--------------------------------------------------------------------------------
1 | package com.scss.settings;
2 |
3 | import com.intellij.codeInsight.daemon.DaemonCodeAnalyzer;
4 | import com.intellij.ide.actions.ShowSettingsUtilImpl;
5 | import com.intellij.openapi.application.ApplicationManager;
6 | import com.intellij.openapi.fileChooser.FileChooserDescriptorFactory;
7 | import com.intellij.openapi.options.Configurable;
8 | import com.intellij.openapi.options.ConfigurationException;
9 | import com.intellij.openapi.options.ex.SingleConfigurableEditor;
10 | import com.intellij.openapi.project.Project;
11 | import com.intellij.psi.PsiManager;
12 | import com.intellij.ui.DocumentAdapter;
13 | import com.intellij.ui.HyperlinkLabel;
14 | import com.intellij.ui.TextFieldWithHistory;
15 | import com.intellij.ui.TextFieldWithHistoryWithBrowseButton;
16 | import com.intellij.util.ui.SwingHelper;
17 | import com.intellij.util.ui.UIUtil;
18 | import com.scss.ScssLintProjectComponent;
19 | import com.scss.utils.ScssLintFinder;
20 | import com.scss.utils.ScssLintRunner;
21 | import com.wix.settings.ValidationUtils;
22 | import com.wix.settings.Validator;
23 | import com.wix.ui.PackagesNotificationPanel;
24 | import com.wix.utils.FileUtils;
25 | import org.apache.commons.lang.StringUtils;
26 | import org.jetbrains.annotations.Nls;
27 | import org.jetbrains.annotations.NotNull;
28 | import org.jetbrains.annotations.Nullable;
29 |
30 | import javax.swing.*;
31 | import javax.swing.event.DocumentEvent;
32 | import java.awt.*;
33 | import java.awt.event.ItemEvent;
34 | import java.io.File;
35 | import java.util.ArrayList;
36 | import java.util.List;
37 |
38 | public class ScssLintSettingsPage implements Configurable {
39 | private static final String FIX_IT = "Fix it";
40 | private static final String HOW_TO_USE_SCSS_LINT = "How to Use SCSS Lint";
41 | private static final String HOW_TO_USE_LINK = "https://github.com/idok/scss-lint-plugin";
42 | private final Project project;
43 |
44 | private JCheckBox pluginEnabledCheckbox;
45 | private JPanel panel;
46 | private JPanel errorPanel;
47 | private TextFieldWithHistoryWithBrowseButton scssLintConfigFile;
48 | private JRadioButton searchForConfigInRadioButton;
49 | private JRadioButton useSpecificConfigRadioButton;
50 | private HyperlinkLabel usageLink;
51 | private JLabel ScssLintConfigFilePathLabel;
52 | private JCheckBox treatAllIssuesCheckBox;
53 | private JLabel versionLabel;
54 | private JLabel scssLintExeLabel;
55 | private TextFieldWithHistoryWithBrowseButton scssLintExeField;
56 | private JCheckBox dismissConfigurationHints;
57 | private final PackagesNotificationPanel packagesNotificationPanel;
58 |
59 | public ScssLintSettingsPage(@NotNull final Project project) {
60 | this.project = project;
61 | configESLintBinField();
62 | configScssLintConfigField();
63 | this.packagesNotificationPanel = new PackagesNotificationPanel(project);
64 | errorPanel.add(this.packagesNotificationPanel.getComponent(), BorderLayout.CENTER);
65 | }
66 |
67 | private void addListeners() {
68 | useSpecificConfigRadioButton.addItemListener(e -> scssLintConfigFile.setEnabled(e.getStateChange() == ItemEvent.SELECTED));
69 | pluginEnabledCheckbox.addItemListener(e -> {
70 | boolean enabled = e.getStateChange() == ItemEvent.SELECTED;
71 | setEnabledState(enabled);
72 | });
73 | DocumentAdapter docAdp = new DocumentAdapter() {
74 | protected void textChanged(@NotNull DocumentEvent e) {
75 | updateLaterInEDT();
76 | }
77 | };
78 | scssLintExeField.getChildComponent().getTextEditor().getDocument().addDocumentListener(docAdp);
79 | scssLintConfigFile.getChildComponent().getTextEditor().getDocument().addDocumentListener(docAdp);
80 | }
81 |
82 | private void updateLaterInEDT() {
83 | UIUtil.invokeLaterIfNeeded(ScssLintSettingsPage.this::update);
84 | }
85 |
86 | private void update() {
87 | ApplicationManager.getApplication().assertIsDispatchThread();
88 | validate();
89 | }
90 |
91 | private void setEnabledState(boolean enabled) {
92 | searchForConfigInRadioButton.setEnabled(enabled);
93 | useSpecificConfigRadioButton.setEnabled(enabled);
94 | scssLintConfigFile.setEnabled(enabled && useSpecificConfigRadioButton.isSelected());
95 | scssLintExeField.setEnabled(enabled);
96 | ScssLintConfigFilePathLabel.setEnabled(enabled);
97 | scssLintExeLabel.setEnabled(enabled);
98 | treatAllIssuesCheckBox.setEnabled(enabled);
99 | }
100 |
101 | private void validate() {
102 | Validator validator = new Validator();
103 | if (!ValidationUtils.validatePath(project, scssLintExeField.getChildComponent().getText(), false)) {
104 | validator.add(scssLintExeField.getChildComponent().getTextEditor(), "Path to Scss Lint exe is invalid {{LINK}}", FIX_IT);
105 | }
106 | if (!ValidationUtils.validatePath(project, scssLintConfigFile.getChildComponent().getText(), true)) {
107 | validator.add(scssLintConfigFile.getChildComponent().getTextEditor(), "Path to Scss Lint config is invalid {{LINK}}", FIX_IT); //Please correct path to
108 | }
109 | if (validator.hasErrors()) {
110 | versionLabel.setText("n.a.");
111 | } else {
112 | updateVersion();
113 | }
114 | packagesNotificationPanel.processErrors(validator);
115 | }
116 |
117 | private ScssLintRunner.ScssLintSettings settings;
118 |
119 | private void updateVersion() {
120 | String scssExe = scssLintExeField.getChildComponent().getText();
121 | if (settings != null &&
122 | settings.scssLintExe.equals(scssExe) &&
123 | settings.cwd.equals(project.getBasePath())) {
124 | return;
125 | }
126 | if (StringUtils.isEmpty(scssExe)) {
127 | return;
128 | }
129 | getVersion(scssExe, project.getBasePath());
130 | }
131 |
132 | private void getVersion(String scssExe, String cwd) {
133 | if (StringUtils.isEmpty(scssExe)) {
134 | return;
135 | }
136 | settings = new ScssLintRunner.ScssLintSettings();
137 | settings.scssLintExe = scssExe;
138 | settings.cwd = cwd;
139 | try {
140 | versionLabel.setText(ScssLintRunner.runVersion(settings));
141 | } catch (Exception e) {
142 | versionLabel.setText("error");
143 | e.printStackTrace();
144 | }
145 | }
146 |
147 | private void configESLintBinField() {
148 | TextFieldWithHistory textFieldWithHistory = scssLintExeField.getChildComponent();
149 | textFieldWithHistory.setHistorySize(-1);
150 | textFieldWithHistory.setMinimumAndPreferredWidth(0);
151 |
152 | SwingHelper.addHistoryOnExpansion(textFieldWithHistory, () -> {
153 | // File projectRoot = new File(project.getBaseDir().getPath());
154 | List newFiles = ScssLintFinder.findAllScssLintExe(); //searchForESLintBin(projectRoot);
155 | return FileUtils.toAbsolutePath(newFiles);
156 | });
157 |
158 | SwingHelper.installFileCompletionAndBrowseDialog(project, scssLintExeField, "Select SCSS Lint Exe", FileChooserDescriptorFactory.createSingleFileNoJarsDescriptor());
159 | }
160 |
161 | private void configScssLintConfigField() {
162 | TextFieldWithHistory textFieldWithHistory = scssLintConfigFile.getChildComponent();
163 | textFieldWithHistory.setHistorySize(-1);
164 | textFieldWithHistory.setMinimumAndPreferredWidth(0);
165 |
166 | SwingHelper.addHistoryOnExpansion(textFieldWithHistory, () -> {
167 | String f = project.getBasePath();
168 | if (f != null) {
169 | File projectRoot = new File(f);
170 | return ScssLintFinder.searchForLintConfigFiles(projectRoot);
171 | }
172 | return new ArrayList<>();
173 | });
174 |
175 | SwingHelper.installFileCompletionAndBrowseDialog(project, scssLintConfigFile, "Select SCSS Lint Config", FileChooserDescriptorFactory.createSingleFileNoJarsDescriptor());
176 | }
177 |
178 | @Nls
179 | @Override
180 | public String getDisplayName() {
181 | return "SCSS Lint";
182 | }
183 |
184 | @Nullable
185 | @Override
186 | public String getHelpTopic() {
187 | return null;
188 | }
189 |
190 | @Nullable
191 | @Override
192 | public JComponent createComponent() {
193 | loadSettings();
194 | getVersion(scssLintExeField.getChildComponent().getText(), project.getBasePath());
195 | addListeners();
196 | return panel;
197 | }
198 |
199 | @Override
200 | public boolean isModified() {
201 | return pluginEnabledCheckbox.isSelected() != getSettings().pluginEnabled
202 | || dismissConfigurationHints.isSelected() != getSettings().dismissConfigurationHints
203 | || !scssLintExeField.getChildComponent().getText().equals(getSettings().scssLintExecutable)
204 | || treatAllIssuesCheckBox.isSelected() != getSettings().treatAllIssuesAsWarnings
205 | || !getLintConfigFile().equals(getSettings().scssLintConfigFile);
206 | }
207 |
208 | private String getLintConfigFile() {
209 | return useSpecificConfigRadioButton.isSelected() ? scssLintConfigFile.getChildComponent().getText() : "";
210 | }
211 |
212 | @Override
213 | public void apply() throws ConfigurationException {
214 | saveSettings();
215 | PsiManager.getInstance(project).dropResolveCaches();
216 | }
217 |
218 | private void saveSettings() {
219 | Settings settings = getSettings();
220 | settings.pluginEnabled = pluginEnabledCheckbox.isSelected();
221 | settings.scssLintExecutable = scssLintExeField.getChildComponent().getText();
222 | settings.scssLintConfigFile = getLintConfigFile();
223 | settings.treatAllIssuesAsWarnings = treatAllIssuesCheckBox.isSelected();
224 | settings.dismissConfigurationHints = dismissConfigurationHints.isSelected();
225 | project.getComponent(ScssLintProjectComponent.class).validateSettings();
226 | DaemonCodeAnalyzer.getInstance(project).restart();
227 | }
228 |
229 | private void loadSettings() {
230 | Settings settings = getSettings();
231 | pluginEnabledCheckbox.setSelected(settings.pluginEnabled);
232 | scssLintExeField.getChildComponent().setText(settings.scssLintExecutable);
233 | scssLintConfigFile.getChildComponent().setText(settings.scssLintConfigFile);
234 |
235 | boolean hasConfig = StringUtils.isNotEmpty(settings.scssLintConfigFile);
236 | searchForConfigInRadioButton.setSelected(!hasConfig);
237 | useSpecificConfigRadioButton.setSelected(hasConfig);
238 | scssLintConfigFile.setEnabled(hasConfig);
239 | treatAllIssuesCheckBox.setSelected(settings.treatAllIssuesAsWarnings);
240 | dismissConfigurationHints.setSelected(settings.dismissConfigurationHints);
241 | setEnabledState(settings.pluginEnabled);
242 | }
243 |
244 | @Override
245 | public void reset() {
246 | loadSettings();
247 | }
248 |
249 | @Override
250 | public void disposeUIResources() {
251 | }
252 |
253 | protected Settings getSettings() {
254 | return Settings.getInstance(project);
255 | }
256 |
257 | private void createUIComponents() {
258 | // TODO: place custom component creation code here
259 | usageLink = SwingHelper.createWebHyperlink(HOW_TO_USE_SCSS_LINT, HOW_TO_USE_LINK);
260 | }
261 |
262 | public void showSettings() {
263 | String dimensionKey = ShowSettingsUtilImpl.createDimensionKey(this);
264 | SingleConfigurableEditor singleConfigurableEditor = new SingleConfigurableEditor(project, this, dimensionKey, false);
265 | singleConfigurableEditor.show();
266 | }
267 | }
268 |
--------------------------------------------------------------------------------
/scss-lint-plugin/src/main/java/com/scss/settings/Settings.java:
--------------------------------------------------------------------------------
1 | package com.scss.settings;
2 |
3 | import com.intellij.openapi.components.*;
4 | import com.intellij.openapi.project.Project;
5 | import com.intellij.util.xmlb.XmlSerializerUtil;
6 | import org.jetbrains.annotations.NotNull;
7 | import org.jetbrains.annotations.Nullable;
8 |
9 | @State(
10 | name = "ScssLintProjectComponent",
11 | storages = @Storage("scssLintPlugin.xml")
12 | )
13 | public class Settings implements PersistentStateComponent {
14 | public String scssLintConfigFile = "";
15 | public String scssLintExecutable = "";
16 | public boolean treatAllIssuesAsWarnings;
17 | public boolean pluginEnabled;
18 | public boolean dismissConfigurationHints;
19 |
20 | public static Settings getInstance(Project project) {
21 | return ServiceManager.getService(project, Settings.class);
22 | }
23 |
24 | @Nullable
25 | @Override
26 | public Settings getState() {
27 | return this;
28 | }
29 |
30 | @Override
31 | public void loadState(@NotNull Settings state) {
32 | XmlSerializerUtil.copyBean(state, this);
33 | }
34 |
35 | public String getVersion() {
36 | return scssLintExecutable + scssLintConfigFile + treatAllIssuesAsWarnings;
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/scss-lint-plugin/src/main/java/com/scss/utils/ScssLintFinder.java:
--------------------------------------------------------------------------------
1 | package com.scss.utils;
2 |
3 | import com.intellij.execution.configurations.PathEnvironmentVariableUtil;
4 | import com.intellij.util.containers.ContainerUtil;
5 | import com.wix.nodejs.NodeFinder;
6 | import com.wix.utils.FileUtils;
7 | import org.jetbrains.annotations.NotNull;
8 |
9 | import java.io.File;
10 | import java.io.FilenameFilter;
11 | import java.util.LinkedHashSet;
12 | import java.util.List;
13 | import java.util.Set;
14 |
15 | public final class ScssLintFinder {
16 | public static final String SCSS_LINT_BASE_NAME = NodeFinder.getBinName("scss-lint");
17 | public static final String SCSS_LINT_YML = "scss-lint.yml";
18 |
19 | private ScssLintFinder() {
20 | }
21 |
22 | @NotNull
23 | public static List findAllScssLintExe() {
24 | // TODO looks like on windows it only searches system path and not user's
25 | List fromPath = PathEnvironmentVariableUtil.findAllExeFilesInPath(SCSS_LINT_BASE_NAME);
26 | Set exes = new LinkedHashSet<>(fromPath);
27 | return ContainerUtil.newArrayList(exes);
28 | }
29 |
30 | /**
31 | * find possible scss-lint config files
32 | * @param projectRoot project root
33 | * @return a list of scss-lint config files
34 | */
35 | public static List searchForLintConfigFiles(final File projectRoot) {
36 | FilenameFilter filter = (file, name) -> name.equals(SCSS_LINT_YML);
37 | List files = FileUtils.recursiveVisitor(projectRoot, filter);
38 | return ContainerUtil.map(files, curFile -> FileUtils.makeRelative(projectRoot, new File(curFile)));
39 | }
40 | }
--------------------------------------------------------------------------------
/scss-lint-plugin/src/main/java/com/scss/utils/ScssLintRunner.java:
--------------------------------------------------------------------------------
1 | package com.scss.utils;
2 |
3 | import com.intellij.execution.ExecutionException;
4 | import com.intellij.execution.configurations.GeneralCommandLine;
5 | import com.intellij.execution.process.ProcessOutput;
6 | import com.intellij.openapi.diagnostic.Logger;
7 | import com.scss.utils.scssLint.Lint;
8 | import com.scss.utils.scssLint.LintResult;
9 | import com.wix.nodejs.NodeRunner;
10 | import org.apache.commons.lang.StringUtils;
11 | import org.jetbrains.annotations.NotNull;
12 | import org.jetbrains.annotations.Nullable;
13 |
14 | import java.io.File;
15 | import java.util.concurrent.TimeUnit;
16 |
17 | public final class ScssLintRunner {
18 | private ScssLintRunner() {
19 | }
20 |
21 | private static final Logger LOG = Logger.getInstance(ScssLintRunner.class);
22 |
23 | private static final int TIME_OUT = (int) TimeUnit.SECONDS.toMillis(120L);
24 | /**
25 | * One or more files specified were not found
26 | */
27 | private static final int FILES_NOT_FOUND = 66;
28 |
29 | public static class ScssLintSettings {
30 | public ScssLintSettings() {
31 | }
32 |
33 | public ScssLintSettings(String config, String cwd, String targetFile, String scssLintExe) {
34 | this.config = config;
35 | this.cwd = cwd;
36 | this.targetFile = targetFile;
37 | this.scssLintExe = scssLintExe;
38 | }
39 |
40 | public String config;
41 | public String cwd;
42 | public String targetFile;
43 | public String scssLintExe;
44 | }
45 |
46 | public static ScssLintSettings buildSettings(@NotNull String cwd, @NotNull String path, @NotNull String scssLintExe, @Nullable String config) {
47 | return new ScssLintSettings(config, cwd, path, scssLintExe);
48 | }
49 |
50 | public static LintResult runLint(@NotNull String cwd, @NotNull String file, @NotNull String scssLintExe, @Nullable String config) {
51 | LintResult result = new LintResult();
52 | try {
53 | ProcessOutput out = lint(cwd, file, scssLintExe, config);
54 | // if (out.getExitCode() == 0) {
55 | // } else {
56 | result.errorOutput = out.getStderr();
57 | try {
58 | if (out.getExitCode() != FILES_NOT_FOUND) {
59 | result.lint = Lint.parse(out.getStdout());
60 | }
61 | } catch (Exception e) {
62 | result.errorOutput = out.getStdout();
63 | }
64 | // }
65 | } catch (Exception e) {
66 | e.printStackTrace();
67 | result.errorOutput = e.toString();
68 | }
69 | return result;
70 | }
71 |
72 | @NotNull
73 | public static ProcessOutput lint(@NotNull String cwd, @NotNull String file, @NotNull String scssLintExe, @Nullable String config) throws ExecutionException {
74 | //scss-lint one.scss -f XML
75 | GeneralCommandLine commandLine = new GeneralCommandLine();
76 | commandLine.setWorkDirectory(cwd);
77 | // if (SystemInfo.isWindows) {
78 | // commandLine.setExePath(settings.eslintExecutablePath);
79 | // } else {
80 | // commandLine.setExePath(settings.node);
81 | // commandLine.addParameter(settings.eslintExecutablePath);
82 | // }
83 | commandLine.setExePath(scssLintExe);
84 | // GeneralCommandLine commandLine = createCommandLine(buildSettings(cwd, file, scssLintExe, config));
85 | commandLine.addParameter(file);
86 | commandLine.addParameter("-f");
87 | commandLine.addParameter("JSON");
88 | // commandLine.addParameter("XML");
89 | if (StringUtils.isNotEmpty(config)) {
90 | commandLine.addParameter("-c");
91 | commandLine.addParameter(config);
92 | }
93 | return NodeRunner.execute(commandLine, TIME_OUT);
94 | }
95 |
96 | @NotNull
97 | private static ProcessOutput version(@NotNull ScssLintSettings settings) throws ExecutionException {
98 | GeneralCommandLine commandLine = createCommandLine(settings);
99 | commandLine.addParameter("-v");
100 | return NodeRunner.execute(commandLine, TIME_OUT);
101 | }
102 |
103 | @NotNull
104 | public static String runVersion(@NotNull ScssLintSettings settings) throws ExecutionException {
105 | if (!new File(settings.scssLintExe).exists()) {
106 | LOG.warn("Calling version with invalid scssLintExe exe " + settings.scssLintExe);
107 | return "";
108 | }
109 | ProcessOutput out = version(settings);
110 | if (out.getExitCode() == 0) {
111 | return out.getStdout().trim();
112 | }
113 | return "";
114 | }
115 |
116 | @NotNull
117 | private static GeneralCommandLine createCommandLine(@NotNull ScssLintSettings settings) {
118 | GeneralCommandLine commandLine = new GeneralCommandLine();
119 | commandLine.setWorkDirectory(settings.cwd);
120 | commandLine.setExePath(settings.scssLintExe);
121 | return commandLine;
122 | }
123 | }
--------------------------------------------------------------------------------
/scss-lint-plugin/src/main/java/com/scss/utils/scssLint/Lint.java:
--------------------------------------------------------------------------------
1 | package com.scss.utils.scssLint;
2 |
3 | import com.google.gson.Gson;
4 | import com.google.gson.GsonBuilder;
5 | import com.google.gson.reflect.TypeToken;
6 |
7 | import java.lang.reflect.Type;
8 | import java.util.List;
9 | import java.util.Map;
10 |
11 | public class Lint {
12 | // public File file;
13 | //
14 | // public static Lint read(String xml) {
15 | // XStream xstream = new XStream();
16 | // xstream.alias("lint", Lint.class);
17 | // xstream.alias("file", File.class);
18 | // xstream.alias("issue", Issue.class);
19 | // xstream.addImplicitCollection(File.class, "issues");
20 | // xstream.useAttributeFor(File.class, "name");
21 | // xstream.useAttributeFor(Issue.class, "linter");
22 | // xstream.useAttributeFor(Issue.class, "line");
23 | // xstream.useAttributeFor(Issue.class, "column");
24 | // xstream.useAttributeFor(Issue.class, "length");
25 | // xstream.useAttributeFor(Issue.class, "severity");
26 | // xstream.useAttributeFor(Issue.class, "reason");
27 | // return (Lint) xstream.fromXML(xml);
28 | // }
29 | //
30 | // public static class File {
31 | // public String name;
32 | // public List issues = new ArrayList();
33 | // }
34 |
35 | public static Map> parse(String json) {
36 | GsonBuilder builder = new GsonBuilder();
37 | // builder.registerTypeAdapterFactory(adapter);
38 | Gson g = builder.setPrettyPrinting().create();
39 | Type listType = new TypeToken
14 | 2.1.0 Allow to dismiss configuration setting notice
15 | 2.0.1 Fix compatibility issue with Idea 2018.1
16 | 2.0.0 Fix compatibility issue with Idea 2018
17 | 1.1.2 Bug fixes
18 | 1.1.1 Bug fixes
19 | 1.1.0 Idea 145 compatibility
20 | 1.0.17 Bug fixes
21 | 1.0.16 Bug fixes
22 | 1.0.15 Bug fixes
23 | 1.0.14 Bug fixes
24 | 1.0.13 Fix compatibility issue with scss-lint 0.39.0
25 | 1.0.12 Bug fixes
26 | 1.0.11 Remove YAML dependency
27 | 1.0.10 Fix PhpStorm compatibility issue
28 | 1.0.9 Fix WebStorm 9 compatibility issue
29 | 1.0.8 Add quick fix to sort properties
30 | 1.0.7 Fixed an NPE bug.
31 | 1.0.6 Window path issue and other bug fixes.
32 | 1.0.5 Bug fixes.
33 | 1.0.4 Bug fixes.
34 | 1.0.3 Fix execution issue on windows.
35 | 1.0.2 Bug fixes.
36 | 1.0.1 First version.
37 | ]]>
38 |
39 | com.intellij.modules.lang
40 |
41 |
42 | com.intellij.css
43 |
44 |
45 |
46 |
47 |
48 |
49 |
51 |
54 |
55 |
56 |
57 |
58 |
59 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 | com.scss.ScssLintProjectComponent
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
--------------------------------------------------------------------------------
/scss-lint-plugin/src/main/resources/com/scss/ScssLintBundle.properties:
--------------------------------------------------------------------------------
1 | #Inspection suppression
2 | unused.property.suppress.for.statement=Suppress for statement
3 | unused.property.suppress.for.block=Suppress for block
4 | unused.property.suppress.for.file=Suppress for file
5 |
6 | #Inspections
7 | scss.inspections.group.name=Sass/SCSS
8 | scss.inspection.group.name=Code quality tools
9 | scss.inspection.undefined.step.name=Undefined step
10 | scss.inspection.undefined.step.msg.name=Undefined step reference:
11 | scss.property.inspection.display.name=SCSS
12 | scss.property.inspection.message=SCSS-LINT: {0} ({1})
13 |
14 | scss.rules.dir.does.not.exist=Rules directory not found. Path {0} not found in project
15 | scss.rules.dir.is.not.a.dir=Rules path is not a directory. Path {0} not found in project
16 |
17 | scss.directory.does.not.exist={0} directory not found. Path {1} not found in project
18 | scss.directory.is.not.a.dir={0} path is not a directory. Path {1} not found in project
19 | scss.path.is.empty=Path to {0} is empty
20 | scss.file.does.not.exist={0} file not found. Path {1} not found in project
21 | scss.file.is.not.a.file={0} path is not a file. Path {1} not found in project
22 |
23 | inspection.fix.sort=Sort properties
24 |
25 | properties.files.inspection.group.display.name=SCSS
26 |
--------------------------------------------------------------------------------
/scss-lint-plugin/src/main/resources/inspectionDescriptions/ScssLintInspection.html:
--------------------------------------------------------------------------------
1 |
2 |
3 | Runs SCSS Lint validator for specified scss file.
4 |
5 |
6 |
--------------------------------------------------------------------------------
/scss-lint-plugin/src/test/java/com/scsslint/ScssLintTest.java:
--------------------------------------------------------------------------------
1 | //package com.scsslint;
2 | //
3 | //import com.intellij.openapi.project.Project;
4 | //import com.intellij.testFramework.fixtures.LightPlatformCodeInsightFixtureTestCase;
5 | //import com.scss.ScssLintExternalAnnotator;
6 | //import com.scss.ScssLintInspection;
7 | //import com.scss.settings.Settings;
8 | ////import org.jetbrains.plugins.scss.SCSSFileType;
9 | //
10 | //public class ScssLintTest extends LightPlatformCodeInsightFixtureTestCase {
11 | // @Override
12 | // protected String getTestDataPath() {
13 | // return TestUtils.getTestDataPath();
14 | // }
15 | //
16 | // @Override
17 | // protected void setUp() throws Exception {
18 | // super.setUp();
19 | // }
20 | //
21 | // @Override
22 | // protected boolean isWriteActionRequired() {
23 | // return false;
24 | // }
25 | //
26 | // private void doTest(final String file) {
27 | // Project project = myFixture.getProject();
28 | // Settings settings = Settings.getInstance(project);
29 | //// settings.scssLintExecutable = ScssLintRunnerTest.SCSS_LINT_BIN;
30 | //// settings.scssLintConfigFile = getTestDataPath() + "/.eslintrc";
31 | //// settings.nodeInterpreter = ScssLintRunnerTest.SCSS_EXE;
32 | //// settings.rulesPath = "";
33 | // settings.pluginEnabled = true;
34 | // myFixture.configureByFile(file);
35 | // myFixture.enableInspections(new ScssLintInspection());
36 | // myFixture.checkHighlighting(true, false, true);
37 | // }
38 | //
39 | // private void doTest() {
40 | // String name = getTestName(false).replaceAll("_", "-");
41 | // doTest("/inspections/" + name + '.' + ScssLintExternalAnnotator.SCSS);
42 | // }
43 | //
44 | // public void testCapitalizationInSelector() {
45 | // doTest();
46 | // }
47 | //
48 | // public void testEmptyRule() {
49 | // doTest();
50 | // }
51 | //
52 | // public void testHexLength() {
53 | // doTest();
54 | // }
55 | //}
56 |
--------------------------------------------------------------------------------
/scss-lint-plugin/src/test/java/com/scsslint/TestUtils.java:
--------------------------------------------------------------------------------
1 | package com.scsslint;
2 |
3 | import com.intellij.openapi.diagnostic.Logger;
4 |
5 | import java.io.File;
6 | import java.net.URISyntaxException;
7 | import java.net.URL;
8 |
9 | /**
10 | * @author idok
11 | */
12 | public final class TestUtils {
13 |
14 | private TestUtils() {
15 | }
16 |
17 | private static final Logger LOG = Logger.getInstance(TestUtils.class);
18 |
19 | private static String TEST_DATA_PATH;
20 |
21 | public static String getTestDataPath() {
22 | if (TEST_DATA_PATH == null) {
23 | ClassLoader loader = TestUtils.class.getClassLoader();
24 | URL resource = loader.getResource("testData");
25 | try {
26 | TEST_DATA_PATH = new File("testData").getAbsolutePath();
27 | if (resource != null) {
28 | TEST_DATA_PATH = new File(resource.toURI()).getPath().replace(File.separatorChar, '/');
29 | }
30 | } catch (URISyntaxException e) {
31 | LOG.error(e);
32 | return null;
33 | }
34 | }
35 | return TEST_DATA_PATH;
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/scss-lint-plugin/src/test/java/com/scsslint/TestUtils2.java:
--------------------------------------------------------------------------------
1 | package com.scsslint;
2 |
3 | import com.intellij.openapi.application.PathManager;
4 | import com.intellij.openapi.diagnostic.Logger;
5 | import com.intellij.openapi.roots.ModifiableRootModel;
6 | import com.intellij.openapi.roots.ModuleRootManager;
7 | import com.intellij.openapi.roots.OrderEnumerator;
8 | import com.intellij.openapi.roots.OrderRootType;
9 | import com.intellij.openapi.roots.libraries.Library;
10 | import com.intellij.openapi.roots.libraries.LibraryTable;
11 | import com.intellij.openapi.util.io.FileUtil;
12 | import com.intellij.openapi.vfs.VfsUtil;
13 | import com.intellij.util.Processor;
14 | import org.jetbrains.annotations.NotNull;
15 | import org.jetbrains.annotations.Nullable;
16 |
17 | import java.io.File;
18 | import java.net.URISyntaxException;
19 | import java.net.URL;
20 | import java.util.List;
21 |
22 | /**
23 | * @author ilyas
24 | */
25 | public final class TestUtils2 {
26 |
27 | public static final String BASE_TEST_DATA_PATH = findTestDataPath();
28 | public static final String SDK_HOME_PATH = BASE_TEST_DATA_PATH + "/sdk";
29 |
30 | private TestUtils2() {
31 | }
32 |
33 | private static String findTestDataPath() {
34 | final File f = new File("/Users/idok/Projects/eslint-plugin/testData"); // launched from 'Dart-plugin' project
35 | if (f.isDirectory()) return FileUtil.toSystemIndependentName(f.getAbsolutePath());
36 |
37 | // PathManager.get
38 | return FileUtil.toSystemIndependentName(PathManager.getHomePath() + "/testData");
39 | }
40 |
41 | private static final Logger LOG = Logger.getInstance("org.jetbrains.plugins.clojure.util.TestUtils");
42 |
43 | private static final String[] RUN_PATHS = {
44 | "out/test/clojure-plugin",
45 | // if tests are run using ant script
46 | "dist/testClasses"};
47 |
48 | private static String TEST_DATA_PATH;
49 |
50 | public static final String CARET_MARKER = "";
51 | public static final String BEGIN_MARKER = "";
52 | public static final String END_MARKER = "";
53 |
54 | public static String getTestDataPath() {
55 | if (TEST_DATA_PATH == null) {
56 | ClassLoader loader = TestUtils2.class.getClassLoader();
57 | URL resource = loader.getResource("testData");
58 | try {
59 | TEST_DATA_PATH = new File("testData").getAbsolutePath();
60 | if (resource != null) {
61 | TEST_DATA_PATH = new File(resource.toURI()).getPath().replace(File.separatorChar, '/');
62 | }
63 | } catch (URISyntaxException e) {
64 | LOG.error(e);
65 | return null;
66 | }
67 | }
68 | return TEST_DATA_PATH;
69 | }
70 |
71 | public static String getMockJdk() {
72 | return getTestDataPath() + "/mockJDK";
73 | }
74 |
75 |
76 | public static String getMockClojureLib() {
77 | return getTestDataPath() + "/mockClojureLib/clojure-1.5.jar";
78 | }
79 |
80 | public static String getMockClojureContribLib() {
81 | return getTestDataPath() + "/mockClojureLib/clojure-contrib.jar";
82 | }
83 |
84 | @Nullable
85 | public static String getDataPath(@NotNull Class> clazz) {
86 | final String classDir = getClassRelativePath(clazz);
87 | String moduleDir = getModulePath(clazz);
88 | return classDir != null && moduleDir != null ? moduleDir + "/" + classDir + "/data/" : null;
89 | }
90 |
91 | public static String getOutputPath(final Class> clazz) {
92 | final String classDir = getClassRelativePath(clazz);
93 | String moduleDir = getModulePath(clazz);
94 | return classDir != null && moduleDir != null ? moduleDir + "/" + classDir + "/output/" : null;
95 | }
96 |
97 | @Nullable
98 | public static String getDataPath(@NotNull Class> s, @NotNull final String relativePath) {
99 | return getDataPath(s) + "/" + relativePath;
100 | }
101 |
102 | @Nullable
103 | public static String getClassRelativePath(@NotNull Class> s) {
104 | String classFullPath = getClassFullPath(s);
105 | for (String path : RUN_PATHS) {
106 | final String dataPath = getClassDirPath(classFullPath, path);
107 | if (dataPath != null) {
108 | return dataPath;
109 | }
110 | }
111 | return null;
112 | }
113 |
114 | @Nullable
115 | public static String getModulePath(@NotNull Class> s) {
116 | String classFullPath = getClassFullPath(s);
117 | for (String path : RUN_PATHS) {
118 | final String dataPath = getModulePath(classFullPath, path);
119 | if (dataPath != null) {
120 | return dataPath;
121 | }
122 | }
123 | return null;
124 | }
125 |
126 | public static String getClassFullPath(@NotNull final Class> s) {
127 | String name = s.getSimpleName() + ".class";
128 | final URL url = s.getResource(name);
129 | return url.getPath();
130 | }
131 |
132 | @Nullable
133 | private static String getModulePath(@NotNull String s, @NotNull final String indicator) {
134 | int n = s.indexOf(indicator);
135 | if (n == -1) {
136 | return null;
137 | }
138 | return s.substring(0, n - 1);
139 | }
140 |
141 | @Nullable
142 | private static String getClassDirPath(@NotNull String s, @NotNull final String indicator) {
143 | int n = s.indexOf(indicator);
144 | if (n == -1) {
145 | return null;
146 | }
147 | s = "test" + s.substring(n + indicator.length());
148 | s = s.substring(0, s.lastIndexOf('/'));
149 | return s;
150 | }
151 |
152 | public static ModifiableRootModel addLibrary(ModifiableRootModel rootModel,
153 | ModuleRootManager rootManager, OrderEnumerator libs,
154 | List libModels,
155 | final String clojureLibraryName, String mockLib, String mockLibSrc) {
156 | class CustomProcessor implements Processor {
157 | private boolean result = true;
158 |
159 | public boolean process(Library library) {
160 | boolean res = library.getName().equals(clojureLibraryName);
161 | if (res) result = false;
162 | return result;
163 | }
164 | }
165 | CustomProcessor processor = new CustomProcessor();
166 | libs.forEachLibrary(processor);
167 | if (processor.result) {
168 | if (rootModel == null) {
169 | rootModel = rootManager.getModifiableModel();
170 | }
171 | final LibraryTable libraryTable = rootModel.getModuleLibraryTable();
172 | final Library scalaLib = libraryTable.createLibrary(clojureLibraryName);
173 | final Library.ModifiableModel libModel = scalaLib.getModifiableModel();
174 | libModels.add(libModel);
175 | addLibraryRoots(libModel, mockLib, mockLibSrc);
176 | }
177 | return rootModel;
178 | }
179 |
180 | public static void addLibraryRoots(Library.ModifiableModel libModel, String mockLib, String mockLibSrc) {
181 | final File libRoot = new File(mockLib);
182 | assert libRoot.exists();
183 |
184 | libModel.addRoot(VfsUtil.getUrlForLibraryRoot(libRoot), OrderRootType.CLASSES);
185 | if (mockLibSrc != null) {
186 | final File srcRoot = new File(mockLibSrc);
187 | assert srcRoot.exists();
188 | libModel.addRoot(VfsUtil.getUrlForLibraryRoot(srcRoot), OrderRootType.SOURCES);
189 | }
190 | // ((VirtualFilePointerManagerImpl) VirtualFilePointerManager.getInstance()).storePointers();
191 | }
192 |
193 | }
194 |
--------------------------------------------------------------------------------
/scss-lint-plugin/src/test/java/com/scsslint/utils/ConfigFinderTest.java:
--------------------------------------------------------------------------------
1 | //package com.scsslint.utils;
2 | //
3 | //import com.scss.utils.ConfigFinder;
4 | //import com.scss.utils.ScssLintRunner;
5 | //import org.junit.Test;
6 | //import static com.scsslint.utils.Settings.*;
7 | //
8 | //public class ConfigFinderTest {
9 | // public static final String CONFIG = "";
10 | //
11 | // private static ScssLintRunner.ScssLintSettings createSettings(String targetFile) {
12 | // return ScssLintRunner.buildSettings(PLUGIN_ROOT, targetFile, SCSS_EXE, CONFIG);
13 | // }
14 | //
15 | // private static ScssLintRunner.ScssLintSettings createSettings() {
16 | // return createSettings("");
17 | // }
18 | //
19 | // @Test
20 | // public void testMultiply() {
21 | // ConfigFinder.INSTANCE.readConfig("~/Projects/packages-plugin-test", "/Users/idok/Projects/packages-plugin-test/scss/.scss-lint.yml");
22 | // }
23 | //}
24 |
--------------------------------------------------------------------------------
/scss-lint-plugin/src/test/java/com/scsslint/utils/PrintAppDataDir.java:
--------------------------------------------------------------------------------
1 | //package com.scsslint.utils;
2 | //
3 | //import com.sun.jna.Library;
4 | //import com.sun.jna.Native;
5 | //import com.sun.jna.NativeMapped;
6 | //import com.sun.jna.PointerType;
7 | //import com.sun.jna.win32.W32APIFunctionMapper;
8 | //import com.sun.jna.win32.W32APITypeMapper;
9 | //
10 | //import java.util.HashMap;
11 | //import java.util.Map;
12 | //
13 | //public class PrintAppDataDir {
14 | //
15 | // public static void main(String[] args) {
16 | // if (com.sun.jna.Platform.isWindows()) {
17 | // HWND hwndOwner = null;
18 | // int nFolder = Shell32.CSIDL_LOCAL_APPDATA;
19 | // HANDLE hToken = null;
20 | // int dwFlags = Shell32.SHGFP_TYPE_CURRENT;
21 | // char[] pszPath = new char[Shell32.MAX_PATH];
22 | // int hResult = Shell32.INSTANCE.SHGetFolderPath(hwndOwner, nFolder, hToken, dwFlags, pszPath);
23 | // if (Shell32.S_OK == hResult) {
24 | // String path = new String(pszPath);
25 | // int len = path.indexOf('\0');
26 | // path = path.substring(0, len);
27 | // System.out.println(path);
28 | // } else {
29 | // System.err.println("Error: " + hResult);
30 | // }
31 | // }
32 | // }
33 | //
34 | // private static Map OPTIONS = new HashMap();
35 | //
36 | // static {
37 | // OPTIONS.put(Library.OPTION_TYPE_MAPPER, W32APITypeMapper.UNICODE);
38 | // OPTIONS.put(Library.OPTION_FUNCTION_MAPPER,
39 | // W32APIFunctionMapper.UNICODE);
40 | // }
41 | //
42 | // static class HANDLE extends PointerType implements NativeMapped {
43 | // }
44 | //
45 | // static class HWND extends HANDLE {
46 | // }
47 | //
48 | // static interface Shell32 extends Library {
49 | //
50 | // public static final int MAX_PATH = 260;
51 | // public static final int CSIDL_LOCAL_APPDATA = 0x001c;
52 | // public static final int SHGFP_TYPE_CURRENT = 0;
53 | // public static final int SHGFP_TYPE_DEFAULT = 1;
54 | // public static final int S_OK = 0;
55 | //
56 | // static Shell32 INSTANCE = (Shell32) Native.loadLibrary("shell32", Shell32.class, OPTIONS);
57 | //
58 | // /**
59 | // * see http://msdn.microsoft.com/en-us/library/bb762181(VS.85).aspx
60 | // *
61 | // * HRESULT SHGetFolderPath( HWND hwndOwner, int nFolder, HANDLE hToken,
62 | // * DWORD dwFlags, LPTSTR pszPath);
63 | // */
64 | // public int SHGetFolderPath(HWND hwndOwner, int nFolder, HANDLE hToken, int dwFlags, char[] pszPath);
65 | // }
66 | //}
--------------------------------------------------------------------------------
/scss-lint-plugin/src/test/java/com/scsslint/utils/ScssLintRunner2Test.java:
--------------------------------------------------------------------------------
1 | //package com.scsslint.utils;
2 | //
3 | //import com.intellij.execution.ExecutionException;
4 | //import com.intellij.execution.configurations.PathEnvironmentVariableUtil;
5 | //import com.scss.utils.ScssLintFinder;
6 | //import com.scss.utils.ScssLintRunner;
7 | //import com.scss.utils.scssLint.LintResult;
8 | //import org.junit.Test;
9 | //
10 | //import java.io.File;
11 | //import java.util.List;
12 | //
13 | //import static org.junit.Assert.assertEquals;
14 | //import static com.scsslint.utils.Settings.*;
15 | //
16 | //public class ScssLintRunner2Test {
17 | // private static final String CONFIG = "";
18 | //
19 | // private static ScssLintRunner.ScssLintSettings createSettings(String targetFile) {
20 | // return ScssLintRunner.buildSettings(PLUGIN_ROOT, targetFile, SCSS_EXE, CONFIG);
21 | // }
22 | //
23 | // private static ScssLintRunner.ScssLintSettings createSettings() {
24 | // return createSettings("");
25 | // }
26 | //
27 | // @Test
28 | // public void testLint() {
29 | // String scssFile = "testData/one.scss";
30 | // ScssLintRunner.ScssLintSettings settings = createSettings(scssFile);
31 | // LintResult result = ScssLintRunner.runLint(settings.cwd, settings.targetFile, SCSS_EXE, CONFIG);
32 | // assertEquals("should have 1 issue", 1, result.lint.get(scssFile).size());
33 | // assertEquals("should have props warn", "Properties should be ordered color, font", result.lint.get(scssFile).get(0).reason);
34 | // }
35 | //
36 | // @Test
37 | // public void findExeInPath() {
38 | // List fromPath = PathEnvironmentVariableUtil.findAllExeFilesInPath(ScssLintFinder.SCSS_LINT_BASE_NAME);
39 | // System.out.println(fromPath);
40 | // assertEquals("should find exe", "/usr/local/bin/scss-lint", fromPath.get(0).toString());
41 | // }
42 | //
43 | // @Test
44 | // public void testVersion() {
45 | // ScssLintRunner.ScssLintSettings settings = createSettings();
46 | // try {
47 | // String version = ScssLintRunner.runVersion(settings);
48 | // assertEquals("version should be", "scss-lint 0.38.0", version);
49 | // } catch (ExecutionException e) {
50 | // e.printStackTrace();
51 | // }
52 | // }
53 | //}
54 |
--------------------------------------------------------------------------------
/scss-lint-plugin/src/test/java/com/scsslint/utils/ScssLintRunnerTest.java:
--------------------------------------------------------------------------------
1 | package com.scsslint.utils;
2 |
3 | import com.intellij.execution.configurations.PathEnvironmentVariableUtil;
4 | import com.scss.utils.ScssLintFinder;
5 | import com.scss.utils.ScssLintRunner;
6 | import org.junit.Test;
7 |
8 | import java.io.File;
9 | import java.util.Arrays;
10 | import java.util.List;
11 |
12 | import static com.scsslint.utils.Settings.PLUGIN_ROOT;
13 | import static com.scsslint.utils.Settings.SCSS_EXE;
14 | import static org.junit.Assert.assertArrayEquals;
15 | import static org.junit.Assert.assertEquals;
16 |
17 | public class ScssLintRunnerTest {
18 | public static final String CONFIG = "";
19 |
20 | private static ScssLintRunner.ScssLintSettings createSettings(String targetFile) {
21 | return ScssLintRunner.buildSettings(PLUGIN_ROOT, targetFile, SCSS_EXE, CONFIG);
22 | }
23 |
24 | private static ScssLintRunner.ScssLintSettings createSettings() {
25 | return createSettings("");
26 | }
27 |
28 | // @Test
29 | // public void testMultiply() {
30 | // String scssFile = "testData/one.scss";
31 | //// String scssFile = PLUGIN_ROOT + "/testData/one.scss";
32 | // ScssLintRunner.ScssLintSettings settings = createSettings(scssFile);
33 | // LintResult result = ScssLintRunner.runLint(settings.cwd, settings.targetFile, SCSS_EXE, CONFIG);
34 | //// System.out.println(result.lint.file.name);
35 | //// System.out.println(result.lint.file.issues.size());
36 | //// assertEquals("file name should match", scssFile, result.lint.get(scssFile));
37 | // assertNotNull(result.lint);
38 | // assertEquals("should have 1 issue", 1, result.lint.get(scssFile).size());
39 | // }
40 |
41 | @Test
42 | public void testFindAllExeFilesInPath() {
43 | List fromPath = PathEnvironmentVariableUtil.findAllExeFilesInPath(ScssLintFinder.SCSS_LINT_BASE_NAME);
44 | // System.out.println(fromPath);
45 | assertEquals("should have size", 2, fromPath.size());
46 | assertArrayEquals("should have 2 paths", Arrays.asList("/usr/local/bin/scss-lint", "/usr/local/bin/scss-lint").toArray(), fromPath.stream().map(File::toString).toArray());
47 | }
48 |
49 | // @Test
50 | // public void testVersion() {
51 | // ScssLintRunner.ScssLintSettings settings = createSettings();
52 | // try {
53 | // String version = ScssLintRunner.runVersion(settings);
54 | // assertEquals("version should be", "scss-lint 0.27.0", version);
55 | // } catch (ExecutionException e) {
56 | // e.printStackTrace();
57 | // }
58 | // }
59 | }
60 |
--------------------------------------------------------------------------------
/scss-lint-plugin/src/test/java/com/scsslint/utils/Settings.java:
--------------------------------------------------------------------------------
1 | package com.scsslint.utils;
2 |
3 | public final class Settings {
4 | static final String SCSS_EXE = "/usr/local/bin/scss-lint";
5 | static final String PLUGIN_ROOT = "/Users/idok/projects/idea-plugins/scss-lint-plugin/scss-lint-plugin";
6 | public static final String CONFIG = "";
7 |
8 | private Settings() {
9 | }
10 | }
11 |
--------------------------------------------------------------------------------
/scss-lint-plugin/src/test/java/log4j.properties:
--------------------------------------------------------------------------------
1 |
2 | # Set root logger level to DEBUG and its only appender to A1.
3 | log4j.rootLogger=WARN, A1
4 |
5 | # A1 is set to be a ConsoleAppender.
6 | log4j.appender.A1=org.apache.log4j.ConsoleAppender
7 |
8 | # A1 uses PatternLayout.
9 | log4j.appender.A1.layout=org.apache.log4j.PatternLayout
10 | log4j.appender.A1.layout.ConversionPattern=%-4r [%t] %-5p %c %x - %m%n
11 |
12 | #com.intellij.ide.plugins.PluginBean
--------------------------------------------------------------------------------
/scss-lint-plugin/src/test/resources/.scss-lint.yml:
--------------------------------------------------------------------------------
1 | #inherit_from: '../../inherited-config.yml'
2 |
3 | exclude: 'app/assets/stylesheets/plugins/**'
4 |
5 | linters:
6 | BorderZero:
7 | enabled: false
8 |
9 | Indentation:
10 | exclude:
11 | - 'path/to/file.scss'
12 | - 'path/to/directory/**'
13 | severity: warning
14 | width: 2
--------------------------------------------------------------------------------
/scss-lint-plugin/src/test/resources/inspections/CapitalizationInSelector.scss:
--------------------------------------------------------------------------------
1 | .shortOrLong {
2 | color: #f2e;
3 | }
4 |
--------------------------------------------------------------------------------
/scss-lint-plugin/src/test/resources/inspections/EmptyRule.scss:
--------------------------------------------------------------------------------
1 | .cat {
2 | }
--------------------------------------------------------------------------------
/scss-lint-plugin/src/test/resources/inspections/HexLength.scss:
--------------------------------------------------------------------------------
1 |
2 | .short-or-long {
3 | color: #ff22ee;
4 | }
5 |
6 |
--------------------------------------------------------------------------------
/scss-lint-plugin/src/test/resources/inspections/one.scss:
--------------------------------------------------------------------------------
1 | $font-stack: Helvetica, sans-serif;
2 | $primary-color: #333;
3 |
4 | body {
5 | font: 100% $font-stack;
6 | color: $primary-color;
7 | }
8 |
--------------------------------------------------------------------------------
/scss-lint-plugin/src/test/resources/one.scss:
--------------------------------------------------------------------------------
1 | $font-stack: Helvetica, sans-serif;
2 | $primary-color: #333;
3 |
4 | body {
5 | font: 100% $font-stack;
6 | color: $primary-color;
7 | }
8 |
--------------------------------------------------------------------------------
/scss-lint-plugin/src/test/resources/one.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
6 |
7 |
--------------------------------------------------------------------------------