Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Resolving fix #28

Closed
wants to merge 20 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 34 additions & 4 deletions META-INF/plugin.xml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<idea-plugin version="2">
<id>mobi.hsz.idea.gitignore</id>
<name>.gitignore support</name>
<version>0.4</version>
<version>0.5</version>
<vendor email="[email protected]" url="http://www.hsz.mobi">hsz</vendor>

<description><![CDATA[
Expand All @@ -23,6 +23,10 @@
<li>Generate Gitignore rules basing on <a href="https://github.com/github/gitignore">GitHub's templates collection</a></li>
<li>Add selected file/directory to Gitignore rules from popup menu</li>
<li>Suggesting .gitignore file creation for new project</li>
<li>Entries inspection (duplicated, covered, unused)</li>
<li>Comments and brackets support</li>
<li>Navigation to entries in Project view</li>
<li>Renaming entries from Gitignore file</li>
</ul>

<b><i>Feature requests:</i></b>
Expand All @@ -41,6 +45,27 @@
]]></description>

<change-notes><![CDATA[
Version 0.5
<br/><br/>
<i>Many thanks to <a href="https://github.com/zolotov">@zolotov</a> for his great support.</i>
<br/><br/>
<ul>
<li>Comments support with <kbd>Ctrl</kbd> + <kbd>/</kbd> shortcut</li>
<li>Brackets support</li>
<li>Generator dialog enhancement (<a href="https://github.com/zolotov">@zolotov</a>)</li>
<li>Duplicate entry inspection</li>
<li>Cover entry inspection (checks if entry includes another one)</li>
<li>Unused entry inspection</li>
<li>Remove entry quick fix (<a href="https://github.com/zolotov">@zolotov</a>)</li>
<li>Entry reference navigation with <kbd>Ctrl</kbd> + <kbd>click</kbd> (<a href="https://github.com/zolotov">@zolotov</a>)</li>
<li>Rename entry refactoring (<a href="https://github.com/zolotov">@zolotov</a>)</li>
<li>Color schemes update (introduced bracket, value, slash; removed file, directory)</li>
<li>Directory line marker</li>
<li>Multi-gitignore files support for adding from context menu</li>
<li>Prevent adding duplicate entries (<a href="https://github.com/hsz/idea-gitignore/issues/17">#17</a>)</li>
<li><i>and many more...</i></li>
</ul>

Version 0.4
<ul>
<li>Show ignored files by specified Gitignore file (right click on <i>.gitignore</i> file)</li>
Expand Down Expand Up @@ -117,7 +142,7 @@

<codeInsight.lineMarkerProvider
language="Gitignore"
implementationClass="mobi.hsz.idea.gitignore.daemon.GitignoreLineMarkerProvider"/>
implementationClass="mobi.hsz.idea.gitignore.daemon.GitignoreDirectoryMarkerProvider"/>

<colorSettingsPage
implementation="mobi.hsz.idea.gitignore.highlighter.GitignoreColorSettingsPage"/>
Expand Down Expand Up @@ -167,7 +192,7 @@
implementationClass="mobi.hsz.idea.gitignore.codeInspection.GitignoreUnusedEntryInspection"
key="codeInspection.unusedEntry"
language="Gitignore"
level="INFO"/>
level="WEAK WARNING"/>

<psi.referenceContributor
language="Gitignore"
Expand All @@ -187,8 +212,13 @@
<action id="Gitignore.New" class="mobi.hsz.idea.gitignore.actions.NewFileAction">
<add-to-group group-id="NewGroup" anchor="last"/>
</action>
<group id="Gitignore.IgnoreGroup" class="mobi.hsz.idea.gitignore.actions.IgnoreFileGroupAction" >
<add-to-group group-id="EditorPopupMenu"/>
<add-to-group group-id="ProjectViewPopupMenu"/>
<add-to-group group-id="EditorTabPopupMenu"/>
<add-to-group group-id="ConsoleEditorPopupMenu"/>
</group>
<group>
<action id="Gitignore.Ignore" class="mobi.hsz.idea.gitignore.actions.IgnoreFileAction"/>
<action id="Gitignore.ShowIgnored" class="mobi.hsz.idea.gitignore.actions.ShowIgnoredAction"/>
<add-to-group group-id="EditorPopupMenu"/>
<add-to-group group-id="ProjectViewPopupMenu"/>
Expand Down
28 changes: 27 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,25 @@ To generate new `.gitignore` file, just click on <kbd>File</kbd> > <kbd>New</kbd
Changelog
---------

Version 0.5

*Many thanks to [@zolotov](https://github.com/zolotov) for his great support.*

- Comments support with <kbd>Ctrl</kbd> + <kbd>/</kbd> shortcut
- Brackets support
- Generator dialog enhancement ([@zolotov](https://github.com/zolotov))
- Duplicate entry inspection
- Cover entry inspection (checks if entry includes another one)
- Unused entry inspection
- Remove entry quick fix ([@zolotov](https://github.com/zolotov))
- Entry reference navigation with <kbd>Ctrl</kbd> + <kbd>click</kbd> ([@zolotov](https://github.com/zolotov))
- Rename entry refactoring ([@zolotov](https://github.com/zolotov))
- Color schemes update (introduced bracket, value, slash; removed file, directory)
- Directory line marker
- Multi-gitignore files support for adding from context menu
- Prevent adding duplicate entries ([#17](https://github.com/hsz/idea-gitignore/issues/17))
- *and many more...*

Version 0.4
- Show ignored files by specified Gitignore file (right click on `.gitignore` file)
- Add selected file/directory to Gitignore rules from popup menu
Expand Down Expand Up @@ -138,7 +157,14 @@ Check [`CONTRIBUTING.md`](./CONTRIBUTING.md) file.
Developed By
------------

[**hsz** Jakub Chrzanowski][hsz]
[**@hsz** Jakub Chrzanowski][hsz]


**Contributors**

[**@zolotov** Alexander Zolotov](https://github.com/zolotov)




License
Expand Down
6 changes: 3 additions & 3 deletions resources/bnf/Gitignore.bnf
Original file line number Diff line number Diff line change
Expand Up @@ -29,9 +29,9 @@
gitignoreFile ::= item_ *
private item_ ::= HEADER | SECTION | COMMENT | ENTRY_DIRECTORY | ENTRY_FILE | CRLF
NEGATION ::= "!"
ENTRY_FILE ::= NEGATION ? <<list_macro value_>> { extends="ENTRY" }
ENTRY_DIRECTORY ::= NEGATION ? <<list_macro value_>> SLASH { extends="ENTRY_FILE" }
ENTRY ::= NEGATION ? <<list_macro value_>>
ENTRY_FILE ::= NEGATION ? SLASH ? <<list_macro value_>> { extends="ENTRY" }
ENTRY_DIRECTORY ::= NEGATION ? SLASH ? <<list_macro value_>> SLASH { extends="ENTRY_FILE" }
ENTRY ::= NEGATION ? SLASH ? <<list_macro value_>>

private meta bvalue_ ::= BRACKET_LEFT VALUE BRACKET_RIGHT { pin="BRACKET_LEFT" }
private meta value_ ::= bvalue_ | VALUE
Expand Down
11 changes: 7 additions & 4 deletions resources/messages/GitignoreBundle.properties
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
action.addToGitignore=Add to .gitignore
action.addToGitignore.description=Add this file to .gitignore rules
action.appendFile.entryExists=Entry "{0}" already exists
action.newFile=.gitignore
action.newFile.description=Create new .gitignore file
action.newFile.exists=Gitignore file already exists
Expand All @@ -8,12 +9,14 @@ action.showIgnored=Show ignored files
action.showIgnored.description=Show ignored files matched by Gitignore rules

codeInspection.coverEntry=Cover entry
codeInspection.coverEntry.message="{0}" is covered by "{1}"
codeInspection.coverEntry.message=''#ref'' is covered by {0} #loc
codeInspection.duplicateEntry=Duplicate entry
codeInspection.duplicateEntry.message="{0}" entry is defined more than once
codeInspection.group=Gitignore Inspections
codeInspection.duplicateEntry.message='#ref' entry is defined more than once #loc
codeInspection.group=Gitignore
codeInspection.unusedEntry=Unused entry
codeInspection.unusedEntry.message="{0}" entry is never used
codeInspection.unusedEntry.message='#ref' entry is never used #loc

quick.fix.remove.entry=Remove entry

daemon.lineMarker.directory=Directory entry
daemon.missingGitignore=Missing .gitignore file in GIT project
Expand Down
43 changes: 43 additions & 0 deletions src/mobi/hsz/idea/gitignore/actions/GitignoreRemoveEntryFix.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
package mobi.hsz.idea.gitignore.actions;

import com.intellij.codeInspection.LocalQuickFixOnPsiElement;
import com.intellij.openapi.project.Project;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiFile;
import com.intellij.psi.impl.source.tree.LeafPsiElement;
import mobi.hsz.idea.gitignore.GitignoreBundle;
import mobi.hsz.idea.gitignore.psi.GitignoreEntry;
import mobi.hsz.idea.gitignore.psi.GitignoreTypes;
import org.jetbrains.annotations.NotNull;

public class GitignoreRemoveEntryFix extends LocalQuickFixOnPsiElement {
public GitignoreRemoveEntryFix(@NotNull GitignoreEntry entry) {
super(entry);
}

@NotNull
@Override
public String getText() {
return GitignoreBundle.message("quick.fix.remove.entry");
}

@Override
public void invoke(@NotNull Project project, @NotNull PsiFile psiFile, @NotNull PsiElement startElement, @NotNull PsiElement endElement) {
if (startElement instanceof GitignoreEntry) {
LeafPsiElement crlf = (LeafPsiElement) startElement.getNextSibling();
if (crlf == null || !crlf.getElementType().equals(GitignoreTypes.CRLF)) {
crlf = (LeafPsiElement) startElement.getPrevSibling();
}
if (crlf != null && crlf.getElementType().equals(GitignoreTypes.CRLF)) {
crlf.delete();
}
startElement.delete();
}
}

@NotNull
@Override
public String getFamilyName() {
return GitignoreBundle.message("codeInspection.group");
}
}
27 changes: 20 additions & 7 deletions src/mobi/hsz/idea/gitignore/actions/IgnoreFileAction.java
Original file line number Diff line number Diff line change
Expand Up @@ -7,25 +7,41 @@
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.psi.PsiFile;
import com.intellij.psi.PsiManager;
import mobi.hsz.idea.gitignore.GitignoreBundle;
import mobi.hsz.idea.gitignore.command.AppendFileCommandAction;
import mobi.hsz.idea.gitignore.util.Icons;
import mobi.hsz.idea.gitignore.util.Utils;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

public class IgnoreFileAction extends DumbAwareAction {
VirtualFile gitignoreFile;

public IgnoreFileAction() {
this(null);
}

public IgnoreFileAction(@Nullable VirtualFile virtualFile) {
super(GitignoreBundle.message("action.addToGitignore"), GitignoreBundle.message("action.addToGitignore.description"), Icons.FILE);
gitignoreFile = virtualFile;
}

@Override
public void actionPerformed(AnActionEvent e) {
final VirtualFile file = e.getRequiredData(CommonDataKeys.VIRTUAL_FILE);
final Project project = e.getRequiredData(CommonDataKeys.PROJECT);

PsiFile gitignore = Utils.getGitignoreFile(project);
PsiFile gitignore = null;
if (gitignoreFile != null) {
gitignore = PsiManager.getInstance(project).findFile(gitignoreFile);
}
if (gitignore == null) {
gitignore = Utils.getGitignoreFile(project, null, true);
}

if (gitignore != null) {
String path = getPath(project, file);
String path = getPath(gitignore.getVirtualFile().getParent(), file);
Utils.openFile(project, gitignore);
new AppendFileCommandAction(project, gitignore, path).execute();
}
Expand All @@ -41,11 +57,8 @@ public void update(AnActionEvent e) {
}
}

private static String getPath(@NotNull Project project, @NotNull VirtualFile file) {
String path = StringUtil.notNullize(Utils.getRelativePath(project.getBaseDir(), file));
if (file.isDirectory() && !path.endsWith("/")) {
path += "/";
}
private static String getPath(@NotNull VirtualFile root, @NotNull VirtualFile file) {
String path = StringUtil.notNullize(Utils.getRelativePath(root, file));
return StringUtil.trimStart(path, "/");
}
}
75 changes: 75 additions & 0 deletions src/mobi/hsz/idea/gitignore/actions/IgnoreFileGroupAction.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
package mobi.hsz.idea.gitignore.actions;

import com.intellij.openapi.actionSystem.*;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.ModificationTracker;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.psi.util.CachedValueProvider;
import mobi.hsz.idea.gitignore.GitignoreBundle;
import mobi.hsz.idea.gitignore.util.Icons;
import mobi.hsz.idea.gitignore.util.Utils;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

public class IgnoreFileGroupAction extends ComputableActionGroup {
private final List<VirtualFile> files = new ArrayList<VirtualFile>();
private VirtualFile baseDir;

public IgnoreFileGroupAction() {
Presentation p = getTemplatePresentation();
p.setText(GitignoreBundle.message("action.addToGitignore"));
p.setDescription(GitignoreBundle.message("action.addToGitignore.description"));
p.setIcon(Icons.FILE);
}

@Override
public void update(AnActionEvent e) {
final VirtualFile file = e.getData(CommonDataKeys.VIRTUAL_FILE);
final Project project = e.getData(CommonDataKeys.PROJECT);
files.clear();
if (project != null && file != null) {
files.addAll(Utils.getSuitableGitignoreFiles(project, file));
Collections.reverse(files);
baseDir = project.getBaseDir();
}
setPopup(files.size() > 1);
}

@NotNull
@Override
protected final CachedValueProvider<AnAction[]> createChildrenProvider(@NotNull final ActionManager actionManager) {
return new CachedValueProvider<AnAction[]>() {
@Nullable
@Override
public Result<AnAction[]> compute() {
return Result.create(computeChildren(actionManager), ModificationTracker.EVER_CHANGED);
}
};
}

@NotNull
protected AnAction[] computeChildren(@NotNull ActionManager manager) {
AnAction[] actions;
int size = files.size();
if (size == 0) {
actions = new AnAction[]{ new IgnoreFileAction() };
} else {
actions = new AnAction[size];
for (int i = 0; i < files.size(); i++) {
VirtualFile file = files.get(i);
IgnoreFileAction action = new IgnoreFileAction(file);
actions[i] = action;

if (size > 1) {
String name = Utils.getRelativePath(baseDir, file);
action.getTemplatePresentation().setText(name);
}
}
}
return actions;
}
}
Loading