blob: d4847e4e0a155b96dc793e8f6f97021875be645b [file]
// Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
package com.jetbrains.python.copyright
import com.intellij.openapi.fileTypes.FileType
import com.intellij.openapi.module.Module
import com.intellij.openapi.project.Project
import com.intellij.openapi.vfs.VirtualFile
import com.intellij.psi.PsiComment
import com.intellij.psi.PsiElement
import com.intellij.psi.util.PsiTreeUtil
import com.jetbrains.python.psi.PyFile
import com.maddyhome.idea.copyright.CopyrightProfile
import com.maddyhome.idea.copyright.options.LanguageOptions
import com.maddyhome.idea.copyright.psi.UpdateCopyright
import com.maddyhome.idea.copyright.psi.UpdateCopyrightsProvider
import com.maddyhome.idea.copyright.psi.UpdatePsiFileCopyright
import java.util.function.Predicate
import java.util.regex.Pattern
class PyUpdateCopyrightsProvider : UpdateCopyrightsProvider() {
override fun createInstance(project: Project,
module: Module?,
file: VirtualFile,
base: FileType?,
options: CopyrightProfile?): UpdateCopyright = PyUpdateFileCopyright(project, module, file, options)
override fun getDefaultOptions(): LanguageOptions {
val options = super.getDefaultOptions()
options.block = false
options.fileTypeOverride = LanguageOptions.USE_TEXT
return options
}
}
class PyUpdateFileCopyright(project: Project, module: Module?, root: VirtualFile, options: CopyrightProfile?) : UpdatePsiFileCopyright(
project, module, root, options) {
override fun accept() = file is PyFile
override fun scanFile() {
val f = file as PyFile
val first = if (f.firstChild != null) first(f) else f
for (block in arrayOf(f.importBlock, f.topLevelClasses, f.topLevelAttributes, f.topLevelFunctions)) {
if (block.size > 0) {
checkComments(first, block.first(), true)
return
}
}
checkComments(first, f, true)
}
}
private fun first(file: PyFile): PsiElement = coding(shebang(file.firstChild))
private fun isShebangComment(element: PsiElement) = element is PsiComment && element.text.startsWith("#!")
private fun shebang(element: PsiElement) = if (isShebangComment(element)) {
skipWhitespaceForwardNotNull(element.nextSibling)
}
else {
element
}
private fun skipWhitespaceForwardNotNull(e: PsiElement): PsiElement {
return PsiTreeUtil.skipWhitespacesForward(e) ?: e
}
private val ENCODING_PATTERN: Predicate<String> = Pattern.compile("^[ \\t\\f]*#.*?coding[:=][ \\t]*([-_.a-zA-Z0-9]+)").asPredicate()
private fun isEncodingComment(element: PsiElement) = element is PsiComment && ENCODING_PATTERN.test(element.text)
private fun coding(element: PsiElement) = if (isEncodingComment(element)) {
skipWhitespaceForwardNotNull(element.nextSibling)
}
else {
element
}