Skip to content

Commit 5f8cccd

Browse files
committed
- Added support for completion and file reference (Ctrl+Click, Rename..) for various file and folder related functions and methods
- Added file mode completion support for SplFileInfo::openFile - Added basic file url completion support for header('Location: ... and header('Content-Location: ...
1 parent 5642399 commit 5f8cccd

File tree

11 files changed

+390
-28
lines changed

11 files changed

+390
-28
lines changed

CHANGELOG.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,11 @@
11
Changelog
22
=========
33

4+
### 1.0.2
5+
* Added support for completion and file reference (Ctrl+Click, Rename..) for various file and folder related functions and methods
6+
* Added file mode completion support for SplFileInfo::openFile
7+
* Added basic file url completion support for header('Location: ... and header('Content-Location: ...
8+
49
### 1.0.1
510
* Added infos for date format characters
611
* Added infos for fopen/popen file modes

META-INF/plugin.xml

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,17 @@
11
<idea-plugin version="2">
22
<id>net.king2500.plugins.PhpAdvancedAutoComplete</id>
33
<name>PHP Advanced AutoComplete</name>
4-
<version>1.0.1</version>
4+
<version>1.0.2</version>
55
<vendor email="phpstorm@king2500.net" url="https://github.com/King2500/PhpAdvancedAutoComplete">Thomas Schulz</vendor>
66

77
<description><![CDATA[
88
<p>Adds auto-completion support for various built-in PHP functions and methods, where parameter is a string literal.</p>
99
<p>The following functions are currently supported:</p>
1010
<ul>
1111
<li><b>header/header_remove</b><br>
12-
HTTP response headers, status codes, charsets, mime-types, and much more<br><br></li>
12+
HTTP response headers, status codes, charsets, mime-types, locations, and much more<br><br></li>
13+
<li><b>File and folder related functions and methods (fopen, file_get_contents, dir...)</b><br>
14+
Files and/or folders paths relative to the current file (completion and reference)<br><br></li>
1315
<li><b>date</b><br>
1416
Format characters and common format strings<br><br></li>
1517
<li><b>htmlentities/htmlspecialchars</b><br>
@@ -20,7 +22,7 @@
2022
Known INI variable names<br><br></li>
2123
<li><b>extension_loaded</b><br>
2224
Known PHP extensions<br><br></li>
23-
<li><b>fopen/popen</b><br>
25+
<li><b>fopen/popen/SplFileInfo::openFile</b><br>
2426
File modes<br><br></li>
2527
<li><b>mysql_connect/mysqli_connect/mysqli/PDO</b><br>
2628
Hostnames, database names and usernames from data sources defined in project<br><br></li>
@@ -39,6 +41,13 @@
3941

4042
<change-notes><![CDATA[
4143
44+
<h2>1.0.2</h2>
45+
<ul>
46+
<li>Added support for completion and file reference (Ctrl+Click, Rename..) for various file and folder related functions and methods</li>
47+
<li>Added file mode completion support for SplFileInfo::openFile</li>
48+
<li>Added basic file url completion support for header('Location: ... and header('Content-Location: ...</li>
49+
</ul>
50+
4251
<h2>1.0.1</h2>
4352
<ul>
4453
<li>Added infos for date format characters</li>
@@ -78,6 +87,7 @@
7887
</actions>
7988

8089
<extensions defaultExtensionNs="com.intellij">
90+
<psi.referenceContributor implementation="net.king2500.plugins.PhpAdvancedAutoComplete.PhpFileReferenceContributor"/>
8191
<completion.contributor language="PHP" implementationClass="net.king2500.plugins.PhpAdvancedAutoComplete.PhpFunctionCompletionContributor"/>
8292
</extensions>
8393
</idea-plugin>

PhpAdvancedAutoComplete.jar

12.1 KB
Binary file not shown.

README.md

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,10 @@ Adds auto-completion support for various built-in PHP functions and methods, whe
88
The following functions are currently supported:
99

1010
* <b>header / header_remove</b><br>
11-
HTTP response headers, status codes, charsets, mime-types, and much more
11+
HTTP response headers, status codes, charsets, mime-types, locations, and much more
12+
13+
* <b>File and folder related functions and methods (fopen, file_get_contents, dir...)</b><br>
14+
Files and/or folders paths relative to the current file (completion and reference)
1215

1316
* <b>date</b><br>
1417
Format characters and common format strings
@@ -25,7 +28,7 @@ The following functions are currently supported:
2528
* <b>extension_loaded</b><br>
2629
Known PHP extensions
2730

28-
* <b>fopen / popen</b><br>
31+
* <b>fopen / popen / SplFileInfo::openFile</b><br>
2932
File modes
3033

3134
* <b>mysql_connect/mysqli_connect/mysqli/PDO</b><br>
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
package net.king2500.plugins.PhpAdvancedAutoComplete;
2+
3+
import com.intellij.codeInsight.completion.InsertHandler;
4+
import com.intellij.codeInsight.completion.InsertionContext;
5+
import com.intellij.codeInsight.lookup.LookupElement;
6+
import com.intellij.codeInsight.lookup.LookupElementPresentation;
7+
import com.intellij.psi.PsiElement;
8+
import com.intellij.psi.PsiFileSystemItem;
9+
import org.jetbrains.annotations.NotNull;
10+
import org.jetbrains.annotations.Nullable;
11+
12+
/**
13+
* Created with IntelliJ IDEA.
14+
* User: Thomas
15+
* Date: 16.08.13
16+
* Time: 21:59
17+
*/
18+
public class GenericFileLookupElement extends LookupElement {
19+
private String fileName;
20+
private PsiFileSystemItem psiFile;
21+
private PsiElement psiElement = null;
22+
23+
@Nullable
24+
private InsertHandler<LookupElement> insertHandler = null;
25+
26+
public GenericFileLookupElement(String fileName, PsiFileSystemItem psiFile) {
27+
this.fileName = fileName;
28+
this.psiFile = psiFile;
29+
}
30+
31+
public GenericFileLookupElement(String fileName, PsiFileSystemItem psiFile, PsiElement psiElement, InsertHandler<LookupElement> insertHandler) {
32+
this.fileName = fileName;
33+
this.psiFile = psiFile;
34+
this.insertHandler = insertHandler;
35+
this.psiElement = psiElement;
36+
}
37+
38+
@NotNull
39+
@Override
40+
public String getLookupString() {
41+
return fileName;
42+
}
43+
44+
@NotNull
45+
public Object getObject() {
46+
return this.psiElement != null ? this.psiElement : super.getObject();
47+
}
48+
49+
public void handleInsert(InsertionContext context) {
50+
if (this.insertHandler != null) {
51+
this.insertHandler.handleInsert(context, this);
52+
}
53+
}
54+
55+
public void renderElement(LookupElementPresentation presentation) {
56+
presentation.setItemText(getLookupString());
57+
presentation.setIcon(psiFile.getIcon(0));
58+
//presentation.setTypeText(VfsUtil.getRelativePath(psiFile.getContainingDirectory().getVirtualFile(), psiFile.getProject().getBaseDir(), '/'));
59+
//presentation.setTypeGrayed(true);
60+
}
61+
}
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
package net.king2500.plugins.PhpAdvancedAutoComplete;
2+
3+
import com.intellij.codeInsight.lookup.LookupElement;
4+
import com.intellij.psi.*;
5+
import com.jetbrains.php.lang.psi.elements.StringLiteralExpression;
6+
import net.king2500.plugins.PhpAdvancedAutoComplete.utils.FileHelper;
7+
import org.jetbrains.annotations.NotNull;
8+
import org.jetbrains.annotations.Nullable;
9+
10+
import java.util.ArrayList;
11+
import java.util.List;
12+
import java.util.Map;
13+
14+
/**
15+
* Created with IntelliJ IDEA.
16+
* User: Thomas
17+
* Date: 16.08.13
18+
* Time: 21:29
19+
*/
20+
public class GenericFileReference extends PsiReferenceBase<PsiElement> implements PsiReference {
21+
22+
private String fileName;
23+
private int fileType;
24+
25+
public GenericFileReference(@NotNull StringLiteralExpression element, int type) {
26+
super(element);
27+
28+
fileName = element.getText().substring(
29+
element.getValueRange().getStartOffset(),
30+
element.getValueRange().getEndOffset()
31+
);
32+
33+
fileType = type;
34+
}
35+
36+
@Nullable
37+
@Override
38+
public PsiElement resolve() {
39+
Map<String, PsiFileSystemItem> filesByName = FileHelper.getRelativeFilesByName(getElement().getContainingFile(), fileType);
40+
41+
return filesByName.get(fileName);
42+
}
43+
44+
@NotNull
45+
@Override
46+
public Object[] getVariants() {
47+
List<LookupElement> results = new ArrayList<LookupElement>();
48+
49+
Map<String, PsiFileSystemItem> filesByName = FileHelper.getRelativeFilesByName(getElement().getContainingFile(), fileType);
50+
for (Map.Entry<String, PsiFileSystemItem> entry : filesByName.entrySet()) {
51+
results.add(
52+
new GenericFileLookupElement(entry.getKey(), entry.getValue())
53+
);
54+
}
55+
56+
return results.toArray();
57+
}
58+
}

src/net/king2500/plugins/PhpAdvancedAutoComplete/PhpCompletionTokens.java

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -249,11 +249,14 @@ public class PhpCompletionTokens {
249249
public static String[] mbStringLanguageFuncs = { "mb_language" };
250250
public static String[] mbStringLanguageElements = { "uni", "en", "English", "ja", "Japanese" };
251251

252+
public static String[] obHandlerFuncs = { "ob_start" };
253+
public static String[] obHandlerElements = { "ob_gzhandler" };
254+
252255
public static String[] dateFormatFuncs = { "date" };
253256
public static String[] dateFormatTokens = { "d", "D", "j", "jS", "l", "N", "S", "w", "z", "W", "F", "m", "M", "n", "t", "L", "o", "Y", "y", "a", "A", "B", "g", "G", "h", "H", "i", "s", "u", "e", "I", "O", "P", "T", "Z", "c", "r", "U", "H:i", "H:i:s", "m.d.y", "m.d.Y", "m/d/Y", "d.m.y", "d.m.Y", "d.m.Y H:i:s", "Ymd", "Y-m-d", "Y-m-d H:i:s", "Y/m/d H:i:s", "F j, Y, g:i a" };
254257
public static String[] dateFormatInfos = { "Day of month (01..31)", "Weekday (Mon..Sun)", "Day of month (1..31)", "Day of month (1st..31th)", "Weekday (Monday..Sunday)", "Weekday (1..7)", "Day of month suffix (st, nd, rd, th)", "Weekday (0..6)", "Day of year (0..365)", "Week of year (1..52)", "Month (January..December)", "Month (01..12)", "Month (Jan..Dec)", "Month (1..12)", "Number of days in month (28..31)", "Leap year (1=yes, 0=no)", "Year in ISO-8601 (ex. 2013)", "Year (ex. 2013)", "Year (ex. 13)", "am or pm", "AM or PM", "Swatch Internet time (000..999)", "Hour (1..12)", "Hour (0..23)", "Hour (01..12)", "Hour (00..23)", "Minutes (00..59)", "Seconds (00..59)", "Microseconds (000000..999999)", "Timezone identifier (UTC, GMT, ...)", "Daylight Saving Time (1=yes, 0=no)", "GMT in hours (ex. +0200)", "GMT with colon (ex. +02:00)", "Timezone abbreviation (EST, MDT, ...)", "Timezone offset in seconds (-43200..50400)", "ISO 8601 formatted date", "RFC 2822 formatted date", "Seconds since Jan 1st, 1970", "Hour and minutes", "Hour, minutes and seconds", "Month, day, year", "Month, day, year", "Month, day, year", "Day, month, year", "Day, month, year", "Day, month, year, hour, minutes, seconds", "Year, month, day", "Year, month, day", "Year, month, day, hour, minutes, seconds", "Year, month, day, hour, minutes, seconds", "Month, day, year, hour, minutes, am/pm" };
255258

256-
public static String[] fileModeFuncs = { "fopen", "popen" };
259+
public static String[] fileModeFuncs = { "fopen:1", "popen:1", "SplFileInfo::openFile:0" };
257260
public static String[] fileModeElements = { "r", "r+", "w", "w+", "a", "a+", "x", "x+", "c", "c+" };
258261
public static String[] fileModeInfos = {
259262
"Read from beginning", "Read/write from beginning",
@@ -262,4 +265,6 @@ public class PhpCompletionTokens {
262265
"Create/write from beginning (fails if file exists)", "Create/write/read from beginning (fails if file exists)",
263266
"Create/write from beginning", "Create/write/read from beginning"
264267
};
268+
269+
public static String[] fileFuncs = { "basename:0", "chgrp:0", "chmod:0", "chown:0", "clearstatcache:1", "copy:0", "copy:1", "dirname:0", "file_exists:0", "file_get_contents:0:f", "file_put_contents:0:f", "file:0:f", "fileatime:0", "filectime:0", "filegroup:0", "fileinode:0", "filemtime:0", "fileowner:0", "fileperms:0", "filesize:0:f", "filetype:0:f", "fopen:0:f", "is_dir:0:d", "is_executable:0:f", "is_file:0:f", "is_link:0", "is_readable:0:f", "is_writable:0:f", "is_writeable:0:f", "lchgrp:0", "lchown:0", "link:0", "link:1", "linkinfo:0", "lstat:0", "move_uploaded_file:1:f", "parse_ini_file:0:f", "pathinfo:0", "readfile:0:f", "readlink:0", "realpath:0", "rename:0", "rename:1", "stat:0", "symlink:0", "symlink:1", "touch:0", "unlink:0:f", "dir:0:d", "chdir:0:d", "chroot:0:d", "mkdir:0:d", "rmdir:0:d", "opendir:0:d", "scandir:0:d", "stream_resolve_include_path:0", "SplFileInfo::__construct:0", "SplFileObject::__construct:0", "DirectoryIterator::__construct:0:d", "FilesystemIterator::__construct:0:d", "RecursiveDirectoryIterator::__construct:0:d", "ZipArchive::open:0:f", "ZipArchive::addFile:0:f", "DOMDocument::load:0:f", "simplexml_load_file:0:f", "SimpleXMLElement::asXML:0:f", "SimpleXMLElement::saveXML:0:f", "XMLWriter::openURI:0:f", "xmlwriter_open_uri:0:f", "XMLReader::open:0:f", "imagecreatefromjpeg:0:f", "ImageCreateFromJpeg:0:f", "imagecreatefrompng:0:f", "ImageCreateFromPng:0:f", "imagecreatefromgif:0:f", "ImageCreateFromGif:0:f" };
265270
}
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
package net.king2500.plugins.PhpAdvancedAutoComplete;
2+
3+
import com.intellij.patterns.PlatformPatterns;
4+
import com.intellij.psi.*;
5+
import com.intellij.util.ProcessingContext;
6+
import com.jetbrains.php.lang.PhpLanguage;
7+
import com.jetbrains.php.lang.psi.elements.FunctionReference;
8+
import com.jetbrains.php.lang.psi.elements.MethodReference;
9+
import com.jetbrains.php.lang.psi.elements.ParameterList;
10+
import com.jetbrains.php.lang.psi.elements.StringLiteralExpression;
11+
import com.jetbrains.php.lang.psi.elements.impl.NewExpressionImpl;
12+
import net.king2500.plugins.PhpAdvancedAutoComplete.utils.FileHelper;
13+
import net.king2500.plugins.PhpAdvancedAutoComplete.utils.PhpHelper;
14+
import org.jetbrains.annotations.NotNull;
15+
16+
import java.util.Arrays;
17+
18+
/**
19+
* Created with IntelliJ IDEA.
20+
* User: Thomas
21+
* Date: 16.08.13
22+
* Time: 21:11
23+
*/
24+
public class PhpFileReferenceContributor extends PsiReferenceContributor {
25+
@Override
26+
public void registerReferenceProviders(PsiReferenceRegistrar psiReferenceRegistrar) {
27+
psiReferenceRegistrar.registerReferenceProvider(
28+
PlatformPatterns.psiElement(StringLiteralExpression.class).withLanguage(PhpLanguage.INSTANCE),
29+
new PsiReferenceProvider() {
30+
@NotNull
31+
@Override
32+
public PsiReference[] getReferencesByElement(@NotNull PsiElement psiElement, @NotNull ProcessingContext processingContext) {
33+
if(!(psiElement.getContext() instanceof ParameterList)) {
34+
return new PsiReference[0];
35+
}
36+
37+
ParameterList parameterList = (ParameterList)psiElement.getContext();
38+
39+
if (parameterList == null || !(parameterList.getContext() instanceof FunctionReference || parameterList.getContext() instanceof MethodReference || parameterList.getContext() instanceof NewExpressionImpl)) {
40+
return new PsiReference[0];
41+
}
42+
43+
String funcName = PhpHelper.getCanonicalFuncName(psiElement.getParent().getParent());
44+
int paramIndex = PhpHelper.getParameterIndex(psiElement);
45+
46+
if(Arrays.asList(PhpCompletionTokens.fileFuncs).contains(funcName + ":" + paramIndex + ":f")) {
47+
return new PsiReference[]{ new GenericFileReference((StringLiteralExpression)psiElement, FileHelper.TYPE_FILE ) };
48+
}
49+
else if(Arrays.asList(PhpCompletionTokens.fileFuncs).contains(funcName + ":" + paramIndex + ":d")) {
50+
return new PsiReference[]{ new GenericFileReference((StringLiteralExpression)psiElement, FileHelper.TYPE_DIR ) };
51+
}
52+
else if(Arrays.asList(PhpCompletionTokens.fileFuncs).contains(funcName + ":" + paramIndex)) {
53+
return new PsiReference[]{ new GenericFileReference((StringLiteralExpression)psiElement, FileHelper.TYPE_ALL ) };
54+
}
55+
56+
return new PsiReference[0];
57+
}
58+
}
59+
);
60+
}
61+
}

src/net/king2500/plugins/PhpAdvancedAutoComplete/PhpFunctionCompletionContributor.java

Lines changed: 17 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
import com.jetbrains.php.lang.lexer.PhpTokenTypes;
1212
import com.jetbrains.php.lang.parser.PhpElementTypes;
1313
import net.king2500.plugins.PhpAdvancedAutoComplete.utils.DbHelper;
14+
import net.king2500.plugins.PhpAdvancedAutoComplete.utils.FileHelper;
1415
import net.king2500.plugins.PhpAdvancedAutoComplete.utils.PhpHelper;
1516
import org.jetbrains.annotations.NotNull;
1617

@@ -54,7 +55,7 @@ public void addCompletions(@NotNull CompletionParameters parameters,
5455
boolean resultBold = false;
5556
boolean resultCaseSensitivity = true;
5657

57-
int paramIndex = getParameterIndex(parameters.getPosition().getParent());
58+
int paramIndex = PhpHelper.getParameterIndex(parameters.getPosition().getParent());
5859

5960
if(Arrays.asList(PhpCompletionTokens.iniFuncs).contains(funcName) && paramIndex == 0) {
6061
resultElements = PhpCompletionTokens.iniElements;
@@ -97,7 +98,13 @@ public void addCompletions(@NotNull CompletionParameters parameters,
9798
resultElements = PhpCompletionTokens.phpExtensionElements;
9899
}
99100

100-
if(Arrays.asList(PhpCompletionTokens.fileModeFuncs).contains(funcName) && paramIndex == 1) {
101+
/*
102+
if(Arrays.asList(PhpCompletionTokens.fileFuncs).contains(funcName + ":" + paramIndex)) {
103+
resultElements = FileHelper.getRelativeFiles(parameters.getPosition().getContainingFile().getOriginalFile());
104+
}
105+
*/
106+
107+
if(Arrays.asList(PhpCompletionTokens.fileModeFuncs).contains(funcName + ":" + paramIndex)) {
101108
resultElements = PhpCompletionTokens.fileModeElements;
102109
resultInfos = PhpCompletionTokens.fileModeInfos;
103110
resultBold = true;
@@ -127,6 +134,10 @@ public void addCompletions(@NotNull CompletionParameters parameters,
127134
resultElements = PhpCompletionTokens.mbStringLanguageElements;
128135
}
129136

137+
if(Arrays.asList(PhpCompletionTokens.obHandlerFuncs).contains(funcName) && paramIndex == 0) {
138+
resultElements = PhpCompletionTokens.obHandlerElements;
139+
}
140+
130141
if(Arrays.asList(PhpCompletionTokens.httpHeaderResponseFuncs).contains(funcName) && paramIndex == 0) {
131142
String stringLiteral = parameters.getPosition().getText();
132143
String stringPrefix = stringLiteral.substring(1, stringLiteral.indexOf("IntellijIdeaRulezzz"));
@@ -151,7 +162,8 @@ else if(stringPrefix.startsWith("Content-Language:")) {
151162
resultElements = PhpCompletionTokens.isoLanguageCodes;
152163
}
153164
else if(stringPrefix.startsWith("Content-Location:") || stringPrefix.startsWith("Location:")) {
154-
// TODO: possible locations (.php or .html)
165+
resultElements = prefixArray("/", FileHelper.getProjectFiles(project));
166+
resultElements = concatArrays(new String[] { "/" }, resultElements);
155167
}
156168
else if(stringPrefix.startsWith("Content-Disposition:")) {
157169
resultElements = PhpCompletionTokens.httpContentDispositionTokens;
@@ -226,27 +238,12 @@ else if(!stringPrefix.contains(":")) {
226238
if(resultInfos.length > 0)
227239
builder = builder.withTypeText(resultInfos[i]);
228240

241+
//LookupElement element = builder.withAutoCompletionPolicy(AutoCompletionPolicy.ALWAYS_AUTOCOMPLETE);
242+
//resultSet.addElement(element);
229243
resultSet.addElement(builder);
230244
}
231245
}
232246

233-
private int getParameterIndex(PsiElement paramElement) {
234-
int index = 0;
235-
PsiElement element = paramElement;
236-
237-
while(element != null && element.getPrevSibling() != null) {
238-
String elementClass = element.getPrevSibling().getClass().getSimpleName();
239-
240-
if(elementClass.equals("LeafPsiElement")) {
241-
index++;
242-
}
243-
244-
element = element.getPrevSibling();
245-
}
246-
247-
return index;
248-
}
249-
250247
private String[] concatArrays(String[] A, String[] B) {
251248
int aLen = A.length;
252249
int bLen = B.length;
@@ -263,8 +260,6 @@ private String[] prefixArray(String prefix, String[] array) {
263260
}
264261
return B;
265262
}
266-
267-
268263
}
269264
);
270265
}

0 commit comments

Comments
 (0)