/plugins/copyright/src/com/maddyhome/idea/copyright/util/FileTypeUtil.java

https://bitbucket.org/nbargnesi/idea · Java · 434 lines · 361 code · 55 blank · 18 comment · 101 complexity · d3b5ceb1e861df6938b3c06561ec5905 MD5 · raw file

  1. /*
  2. * Copyright 2000-2012 JetBrains s.r.o.
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. */
  16. package com.maddyhome.idea.copyright.util;
  17. import com.intellij.lang.Commenter;
  18. import com.intellij.lang.LanguageCommenters;
  19. import com.intellij.openapi.components.ServiceManager;
  20. import com.intellij.openapi.diagnostic.Logger;
  21. import com.intellij.openapi.fileTypes.*;
  22. import com.intellij.openapi.project.ProjectCoreUtil;
  23. import com.intellij.openapi.util.text.StringUtil;
  24. import com.intellij.openapi.vfs.VirtualFile;
  25. import com.intellij.psi.PsiDirectory;
  26. import com.intellij.psi.PsiFile;
  27. import com.intellij.util.messages.MessageBus;
  28. import com.maddyhome.idea.copyright.CopyrightUpdaters;
  29. import com.maddyhome.idea.copyright.options.LanguageOptions;
  30. import java.util.*;
  31. public class FileTypeUtil
  32. {
  33. public static synchronized FileTypeUtil getInstance()
  34. {
  35. return ServiceManager.getService(FileTypeUtil.class);
  36. }
  37. public static String buildComment(FileType type, String template, LanguageOptions options)
  38. {
  39. Commenter commenter = getCommenter(type);
  40. if (commenter == null)
  41. {
  42. return "<No comments>";
  43. }
  44. String bs = commenter.getBlockCommentPrefix();
  45. String be = commenter.getBlockCommentSuffix();
  46. String ls = commenter.getLineCommentPrefix();
  47. if ((bs == null || be == null) && ls == null)
  48. {
  49. return "<No comments>";
  50. }
  51. boolean allowBlock = bs != null && be != null;
  52. boolean allowLine = ls != null;
  53. if (allowLine && !allowBlock)
  54. {
  55. bs = ls;
  56. be = ls;
  57. }
  58. boolean allowSeparator = getInstance().allowSeparators(type);
  59. String filler = options.getFiller();
  60. if (!allowSeparator)
  61. {
  62. if (options.getFiller() == LanguageOptions.DEFAULT_FILLER)
  63. {
  64. filler = "~";
  65. }
  66. }
  67. boolean isBlock = options.isBlock();
  68. boolean isPrefix = options.isPrefixLines();
  69. if (isBlock && !allowBlock)
  70. {
  71. isPrefix = true;
  72. }
  73. boolean isBox = options.isBox() && options.isSeparateBefore() && options.isSeparateAfter() &&
  74. options.getLenBefore() == options.getLenAfter();
  75. StringBuffer preview = new StringBuffer(80);
  76. String open = isBlock ? bs : allowLine ? ls : bs;
  77. String close = isBlock ? be : allowLine ? ls : be;
  78. StringBuffer pre = new StringBuffer(5);
  79. StringBuffer leader = new StringBuffer(5);
  80. StringBuffer post = new StringBuffer(5);
  81. if (filler == LanguageOptions.DEFAULT_FILLER)
  82. {
  83. filler = open.substring(open.length() - 1);
  84. }
  85. int offset = 0;
  86. if (isBlock)
  87. {
  88. int pos = open.length() - 1;
  89. pre.append(allowBlock ? filler : open.charAt(pos));
  90. while (pos > 0 && open.charAt(pos) == open.charAt(open.length() - 1))
  91. {
  92. pos--;
  93. offset++;
  94. }
  95. while (open.length() > 1 && pos >= 0)
  96. {
  97. leader.append(' ');
  98. pos--;
  99. }
  100. post.append(filler);
  101. if (!isPrefix)
  102. {
  103. pre = new StringBuffer(0);
  104. }
  105. if (!allowBlock)
  106. {
  107. close = filler;
  108. }
  109. }
  110. else
  111. {
  112. if (allowLine)
  113. {
  114. close = filler;
  115. }
  116. pre.append(open);
  117. post.append(close);
  118. }
  119. int diff = 0;
  120. if (options.isSeparateBefore())
  121. {
  122. if (isBlock && isBox && allowBlock)
  123. {
  124. diff = close.length() - offset;
  125. }
  126. preview.append(open);
  127. for (int i = open.length() + 1; i <= options.getLenBefore() - diff - post.length(); i++)
  128. {
  129. preview.append(filler);
  130. }
  131. preview.append(post);
  132. preview.append('\n');
  133. }
  134. else if (isBlock)
  135. {
  136. preview.append(open).append('\n');
  137. }
  138. if (template.length() > 0)
  139. {
  140. String[] lines = template.split("\n", -1);
  141. for (String line : lines)
  142. {
  143. if (options.isTrim()) {
  144. line = line.trim();
  145. }
  146. line = StringUtil.trimStart(StringUtil.trimStart(line, pre.toString()), open);
  147. line = StringUtil.trimEnd(line, close);
  148. preview.append(leader).append(pre);
  149. int len = 0;
  150. if (pre.length() > 0 && line.length() > 0)
  151. {
  152. preview.append(' ');
  153. len++;
  154. }
  155. preview.append(line);
  156. len += line.length() + leader.length() + pre.length();
  157. if (isBox && len < options.getLenBefore() - diff)
  158. {
  159. for (; len < options.getLenBefore() - diff - post.length(); len++)
  160. {
  161. preview.append(' ');
  162. }
  163. if (isBlock || allowLine)
  164. {
  165. preview.append(post.substring(0, options.getLenBefore() - diff - len));
  166. }
  167. }
  168. if (!isBlock && !allowLine)
  169. {
  170. if (preview.charAt(preview.length() - 1) != ' ')
  171. {
  172. preview.append(' ');
  173. }
  174. preview.append(close);
  175. }
  176. preview.append('\n');
  177. }
  178. }
  179. preview.append(leader);
  180. if (options.isSeparateAfter())
  181. {
  182. preview.append(pre);
  183. for (int i = leader.length() + pre.length(); i < options.getLenAfter() - close.length(); i++)
  184. {
  185. preview.append(filler);
  186. }
  187. preview.append(close);
  188. preview.append('\n');
  189. }
  190. else if (isBlock)
  191. {
  192. if (!allowBlock) {
  193. preview.append(pre).append('\n');
  194. } else {
  195. preview.append(close).append('\n');
  196. }
  197. }
  198. return preview.substring(0, preview.length() - 1);
  199. }
  200. public boolean isSupportedFile(VirtualFile file)
  201. {
  202. if (file == null || file.isDirectory())
  203. {
  204. return false;
  205. }
  206. if (ProjectCoreUtil.isProjectOrWorkspaceFile(file)) return false;
  207. FileType type = file.getFileType();
  208. return types.get(type.getName()) != null;
  209. }
  210. public static boolean isSupportedFile(PsiFile file)
  211. {
  212. if (file == null || file instanceof PsiDirectory)
  213. {
  214. return false;
  215. }
  216. final VirtualFile virtualFile = file.getVirtualFile();
  217. if (virtualFile == null) return false;
  218. if (ProjectCoreUtil.isProjectOrWorkspaceFile(virtualFile)) return false;
  219. return isSupportedType(virtualFile.getFileType());
  220. }
  221. public FileType[] getSupportedTypes()
  222. {
  223. return new HashSet<FileType>(types.values()).toArray(new FileType[]{});
  224. }
  225. public FileType getFileTypeByFile(VirtualFile file)
  226. {
  227. FileType type = file.getFileType();
  228. return getFileTypeByType(type);
  229. }
  230. public FileType getFileTypeByType(FileType type)
  231. {
  232. return types.get(type.getName());
  233. }
  234. public String getFileTypeNameByName(String name)
  235. {
  236. FileType type = types.get(name);
  237. return type != null ? type.getName() : name;
  238. }
  239. public static boolean hasBlockComment(FileType fileType)
  240. {
  241. Commenter commenter = getCommenter(fileType);
  242. return commenter != null && commenter.getBlockCommentPrefix() != null;
  243. }
  244. public static boolean hasLineComment(FileType fileType)
  245. {
  246. Commenter commenter = getCommenter(fileType);
  247. return commenter != null && commenter.getLineCommentPrefix() != null;
  248. }
  249. public boolean allowSeparators(FileType fileType)
  250. {
  251. FileType type = getFileTypeByType(fileType);
  252. return !noSeparators.contains(type);
  253. }
  254. public FileTypeUtil(MessageBus bus)
  255. {
  256. createMappings();
  257. loadFileTypes();
  258. bus.connect().subscribe(FileTypeManager.TOPIC, new FileTypeListener.Adapter() {
  259. @Override
  260. public void fileTypesChanged(FileTypeEvent event) {
  261. loadFileTypes();
  262. }
  263. });
  264. }
  265. private static Commenter getCommenter(FileType fileType)
  266. {
  267. if (fileType instanceof LanguageFileType)
  268. {
  269. return LanguageCommenters.INSTANCE.forLanguage(((LanguageFileType) fileType).getLanguage());
  270. }
  271. return null;
  272. }
  273. private void createMappings()
  274. {
  275. Set<FileType> maps = new HashSet<FileType>();
  276. maps.add(StdFileTypes.DTD);
  277. maps.add(StdFileTypes.XML);
  278. mappings.put(StdFileTypes.XML, maps);
  279. maps = new HashSet<FileType>();
  280. maps.add(StdFileTypes.HTML);
  281. maps.add(StdFileTypes.XHTML);
  282. mappings.put(StdFileTypes.HTML, maps);
  283. maps = new HashSet<FileType>();
  284. maps.add(StdFileTypes.JSP);
  285. mappings.put(StdFileTypes.JSP, maps);
  286. noSeparators.add(StdFileTypes.XML);
  287. noSeparators.add(StdFileTypes.HTML);
  288. noSeparators.add(StdFileTypes.JSP);
  289. noSeparators.add(StdFileTypes.JSPX);
  290. }
  291. private static boolean isSupportedType(FileType type)
  292. {
  293. if (type.isBinary() || type.getName().indexOf("IDEA") >= 0 || "GUI_DESIGNER_FORM".equals(type.getName()))
  294. {
  295. return false;
  296. }
  297. else
  298. {
  299. Commenter commenter = getCommenter(type);
  300. boolean hasComment = commenter != null &&
  301. (commenter.getLineCommentPrefix() != null || commenter.getBlockCommentPrefix() != null);
  302. if (!hasComment)
  303. {
  304. return false;
  305. }
  306. else
  307. {
  308. if (type.equals(StdFileTypes.DTD))
  309. {
  310. return true;
  311. }
  312. else if (type.equals(StdFileTypes.HTML))
  313. {
  314. return true;
  315. }
  316. else if (type.equals(StdFileTypes.XHTML))
  317. {
  318. return true;
  319. }
  320. else if (type.equals(StdFileTypes.PROPERTIES))
  321. {
  322. return true;
  323. }
  324. else if ("JavaScript".equals(type.getName()))
  325. {
  326. return true;
  327. }
  328. }
  329. return CopyrightUpdaters.INSTANCE.forFileType(type) != null;
  330. }
  331. }
  332. private void loadFileTypes()
  333. {
  334. logger.debug("loadFileTypes");
  335. types.clear();
  336. FileType[] ftypes = FileTypeManager.getInstance().getRegisteredFileTypes();
  337. for (FileType ftype : ftypes)
  338. {
  339. // Ignore binary files
  340. // Ignore IDEA specific file types (PROJECT, MODULE, WORKSPACE)
  341. // Ignore GUI Designer files
  342. if (isSupportedType(ftype))
  343. {
  344. logger.debug("adding " + ftype.getName());
  345. Iterator<FileType> iter = mappings.keySet().iterator();
  346. FileType type = ftype;
  347. while (iter.hasNext())
  348. {
  349. FileType fileType = iter.next();
  350. Set<FileType> maps = mappings.get(fileType);
  351. if (maps.contains(ftype))
  352. {
  353. type = fileType;
  354. break;
  355. }
  356. }
  357. types.put(ftype.getName(), type);
  358. }
  359. else
  360. {
  361. logger.debug("ignoring " + ftype.getName());
  362. }
  363. }
  364. }
  365. public FileType getFileTypeByName(String name) {
  366. return types.get(name);
  367. }
  368. public static class SortByName implements Comparator<FileType>
  369. {
  370. public int compare(FileType a, FileType b)
  371. {
  372. return a.getName().compareToIgnoreCase(b.getName());
  373. }
  374. }
  375. private final Map<String, FileType> types = new HashMap<String, FileType>();
  376. private final Map<FileType, Set<FileType>> mappings = new HashMap<FileType, Set<FileType>>();
  377. private final Set<FileType> noSeparators = new HashSet<FileType>();
  378. private static final Logger logger = Logger.getInstance(FileTypeUtil.class.getName());
  379. }