Skip to content

Add linter and guard, apply fixes and suppress by scope#49

Open
WalterWoshid wants to merge 2 commits intoj-plugins:mainfrom
WalterWoshid:feat/apply-fix-and-suppress
Open

Add linter and guard, apply fixes and suppress by scope#49
WalterWoshid wants to merge 2 commits intoj-plugins:mainfrom
WalterWoshid:feat/apply-fix-and-suppress

Conversation

@WalterWoshid
Copy link

Mago inspection now runs lint and guard together with analyze and shows all results in the editor. You can apply Mago autofixes from annotations and suppress issues by statement, function, method, or class. Fixes and suppress actions support intention preview (Ctrl+Q).

Changes

  • Linter and guard – When enabled in settings, the pipeline runs mago lint and mago guard in addition to analyze and merges problems into the same annotations. Lint and guard issues get the same apply-fix and suppress quick fixes as analyze.

  • Better descriptions
    image

  • Apply fix – Apply a single Mago autofix from the problem annotation (Alt+Enter). Fix text uses issue help or message, prefixed with "Mago: ". Before there was a global "Mago: fix the whole file", which only ran the formatter. This has been removed.
    image

  • Apply all by safety – Submenus: "Fix all (safe only)", "Fix all (potentially unsafe)", "Fix all (unsafe)". Each applies only that tier; apply-all uses in-memory edits (no CLI run) so undo works.
    image

  • Mago: Suppress – Quick fix to add @mago-ignore category:code with options: for statement, for function, for method, for class. Submenu when multiple apply. Same-category codes merged into one comment.
    image

  • Format after fix option - Runs the formatter after applying a fix.
    image

  • Platform – Target PhpStorm (PS) 2025.3.2. Remove ReformatFileAction.

Some known bugs/problems/missing stuff

  • The edits are out of sync if Mago is still analyzing after applying an edit. This could be suppressed by removing all annotations until its done analyzing (ugly) or adjusting the edit positions (too much work) or displaying a warning "Please wait for Mago to finish before applying more edits"

  • Sometimes, not sure how to reproduce, the annotations are out of place until Mago is done analyzing.

  • When "format after fix" is run, then hitting the Undo action, PhpStorm asks "Undo Reload from Disk?" which is a slight inconvenience, because the formatter is ran externally. This could be solved by applying the fix on a temporary file, running the formatter on that temporary file, then applying the changes to the editor, without needing 2 actions at once.

  • Suppressing via @mago-ignore on a method or class that already has a PHPDoc will add a second PHPDoc, this should be fixed.

- Run mago lint and guard with analyze; merge results into annotations
- Apply single fix or apply-all by safety (safe / potentially unsafe / unsafe)
- After apply: clear problem cache and restart daemon to avoid stale fixes
  when applying again while Mago is re-analyzing (3–5 s)
- Format after fix: run Mago formatter when the option is enabled in settings
- Mago: Suppress for statement, function, method, class (submenu when multiple);
  always show "for statement" so narrowest scope is available
- Intention preview (Ctrl+Q) for apply and suppress
- Remove ReformatFileAction; fix DaemonCodeAnalyzer.restart deprecation
@WalterWoshid
Copy link
Author

This Pull Request also makes #47 obsolete, because it is included.

@WalterWoshid WalterWoshid force-pushed the feat/apply-fix-and-suppress branch from 654e856 to 3a848ce Compare February 12, 2026 14:21
Copy link
Contributor

@xepozz xepozz left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for improving the plugin, but let's make it a bit clear first

val charStart = String(bytes.copyOf(byteStart), Charsets.UTF_8).length
val charEnd = String(bytes.copyOf(byteEnd), Charsets.UTF_8).length
return charStart until charEnd
private fun runExtraTool(
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

please create a separate class containing all this run logic
together with the lines above that decide to run additional tools

this message processor should not run additional tools.

in general, "quality tools" API looks overcomplicated to implement mago features. you partially implemented some kind of raw quality tool, so I'd suggest you to complete this step and remove all "quality tool" api. would you like to do it?

}
}
} catch (_: Exception) {
// Ignore errors for individual tools
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

add "debug logger" here

import com.jetbrains.php.lang.psi.elements.Method

class MarkIgnoreAction(val code: String, val line: Int) : IntentionAction {
class MagoIgnoreSubmenuAction(
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

please keep 1 class in 1 file

else -> 0
}

fun MagoEdit.maxSafetyLevel(): Int = replacements.maxOfOrNull { safetyLevel(it.safety) } ?: 0
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

put maxSafetyLevel in the MagoEdit instead

Comment on lines +79 to +90
val maxSafetyValue = edits.flatMap { it.replacements }.maxOfOrNull { safetyLevel(it.safety) } ?: 0
val safetySuffix = when (maxSafetyValue) {
2 -> " (unsafe)"
1 -> " (potentially unsafe)"
else -> ""
}
return when {
!fixDescription.isNullOrBlank() -> "Mago: " + fixDescription.trim() + safetySuffix
isApplyAll -> "Mago: Apply all suggested fixes$safetySuffix"
else -> "Mago: Apply suggested fix$safetySuffix"
}
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

use string builder instead


/** Clear cached problems for this file so no fix is offered until the next Mago run. */
fun clearProblemCache(file: PsiFile) {
file.putUserData(MAGO_HTML_LAST_PROBLEMS, null)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

add another function where you put and read there data

file.putUserData(MAGO_HTML_LAST_PROBLEMS, problems)
}

private fun formatGroupedHtmlMessage(problems: List<MagoProblemDescription>): String {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

use buildString

return AnnotationResult(problems)
}

override fun apply(file: PsiFile, annotationResult: AnnotationResult, holder: AnnotationHolder) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

decompose this method

@WalterWoshid
Copy link
Author

Thanks for the review, will do that tommorow :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants