Sign Up
Log In
Log In
or
Sign Up
Places
All Projects
Status Monitor
Collapse sidebar
home:drommer:archlinux
kmozillahelper
_service:download_files:patch-2.patch
Overview
Repositories
Revisions
Requests
Users
Attributes
Meta
File _service:download_files:patch-2.patch of Package kmozillahelper
From 0440cd377bf6a22220cf46114c20ab7518b8d153 Mon Sep 17 00:00:00 2001 From: Fabian Vogt <fabian@ritter-vogt.de> Date: Tue, 30 Nov 2021 14:27:58 +0100 Subject: [PATCH 1/7] Port handleOpen to KIO::OpenUrlJob To work around https://bugs.kde.org/show_bug.cgi?id=446272 (issue #33). --- main.cpp | 18 +++++------------- 1 file changed, 5 insertions(+), 13 deletions(-) diff --git a/main.cpp b/main.cpp index 5472364..21ac5ae 100644 --- a/main.cpp +++ b/main.cpp @@ -48,6 +48,7 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. #include <KIOCore/KRecentDocument> #include <KIOWidgets/KOpenWithDialog> #include <KIOWidgets/KRun> +#include <KIO/OpenUrlJob> #include <KNotifications/KNotification> #include <KService/KMimeTypeTrader> #include <KWindowSystem/KWindowSystem> @@ -479,19 +480,10 @@ bool Helper::handleOpen() mime = getArgument(); if(!allArgumentsUsed()) return false; - // try to handle the case when the server has broken mimetypes and e.g. claims something is application/octet-stream - QMimeType mimeType = QMimeDatabase().mimeTypeForName(mime); - if(!mime.isEmpty() && mimeType.isValid() && KMimeTypeTrader::self()->preferredService(mimeType.name())) - { - return KRun::runUrl(url, mime, NULL, KRun::RunFlags()); // TODO parent - } - else - { - (void) new KRun(url, NULL); // TODO parent - // QObject::connect(run, SIGNAL(finished()), &app, SLOT(openDone())); - // QObject::connect(run, SIGNAL(error()), &app, SLOT(openDone())); - return true; // TODO check for errors? - } + + auto ouj = new KIO::OpenUrlJob(url, mime); + ouj->start(); + return true; } bool Helper::handleReveal() From d084eb3720784a98ee13ea76fa541d3ee4d86ffd Mon Sep 17 00:00:00 2001 From: Brli <brli@chakralinux.org> Date: Sun, 17 Mar 2024 15:13:20 +0800 Subject: [PATCH 2/7] include vscode, clang tools, and cmake-format --- .clang-format | 135 +++++++++++ .clang-tidy | 9 + .cmake-format.yaml | 245 +++++++++++++++++++ .editorconfig | 17 ++ .gitattributes | 11 + .pre-commit-config.yaml | 16 ++ .vscode/settings.json | 218 +++++++++++++++++ CMakeLists.txt | 22 +- main.cpp | 292 +++++++++++----------- main.h | 7 +- tools/run-clang-format.py | 408 +++++++++++++++++++++++++++++++ tools/run-clang-tidy.py | 493 ++++++++++++++++++++++++++++++++++++++ 12 files changed, 1722 insertions(+), 151 deletions(-) create mode 100644 .clang-format create mode 100644 .clang-tidy create mode 100644 .cmake-format.yaml create mode 100644 .editorconfig create mode 100644 .gitattributes create mode 100644 .pre-commit-config.yaml create mode 100644 .vscode/settings.json create mode 100644 tools/run-clang-format.py create mode 100644 tools/run-clang-tidy.py diff --git a/.clang-format b/.clang-format new file mode 100644 index 0000000..3241cee --- /dev/null +++ b/.clang-format @@ -0,0 +1,135 @@ +--- +Language: Cpp +AccessModifierOffset: -4 +AlignAfterOpenBracket: Align +AlignConsecutiveMacros: false +AlignConsecutiveAssignments: false +AlignConsecutiveDeclarations: false +AlignEscapedNewlines: Right +AlignOperands: true +AlignTrailingComments: true +AllowAllArgumentsOnNextLine: false +AllowAllConstructorInitializersOnNextLine: true +AllowAllParametersOfDeclarationOnNextLine: false +AllowShortBlocksOnASingleLine: Never +AllowShortCaseLabelsOnASingleLine: false +AllowShortFunctionsOnASingleLine: None +AllowShortLambdasOnASingleLine: All +AllowShortIfStatementsOnASingleLine: Never +AllowShortLoopsOnASingleLine: false +AlwaysBreakAfterDefinitionReturnType: None +AlwaysBreakAfterReturnType: None +AlwaysBreakBeforeMultilineStrings: false +AlwaysBreakTemplateDeclarations: Yes +BinPackArguments: false +BinPackParameters: false +BraceWrapping: + AfterCaseLabel: true + AfterClass: true + AfterControlStatement: true + AfterEnum: true + AfterFunction: true + AfterNamespace: true + AfterObjCDeclaration: true + AfterStruct: true + AfterUnion: true + AfterExternBlock: true + BeforeCatch: true + BeforeElse: true + IndentBraces: false + SplitEmptyFunction: true + SplitEmptyRecord: true + SplitEmptyNamespace: true +BreakBeforeBinaryOperators: None +BreakBeforeBraces: Custom +BreakBeforeInheritanceComma: false +BreakInheritanceList: BeforeColon +BreakBeforeTernaryOperators: true +BreakConstructorInitializersBeforeComma: false +BreakConstructorInitializers: BeforeColon +BreakAfterJavaFieldAnnotations: false +BreakStringLiterals: true +ColumnLimit: 120 +CommentPragmas: '^ IWYU pragma:' +CompactNamespaces: false +ConstructorInitializerAllOnOneLineOrOnePerLine: false +ConstructorInitializerIndentWidth: 4 +ContinuationIndentWidth: 4 +Cpp11BracedListStyle: true +DeriveLineEnding: true +DerivePointerAlignment: false +DisableFormat: false +ExperimentalAutoDetectBinPacking: false +FixNamespaceComments: true +ForEachMacros: + - foreach + - Q_FOREACH + - BOOST_FOREACH +IncludeBlocks: Preserve +IncludeCategories: + - Regex: '^"(llvm|llvm-c|clang|clang-c)/' + Priority: 2 + SortPriority: 0 + - Regex: '^(<|"(gtest|gmock|isl|json)/)' + Priority: 3 + SortPriority: 0 + - Regex: '.*' + Priority: 1 + SortPriority: 0 +IncludeIsMainRegex: '(Test)?$' +IncludeIsMainSourceRegex: '' +IndentCaseLabels: false +IndentGotoLabels: true +IndentPPDirectives: None +IndentWidth: 4 +IndentWrappedFunctionNames: false +JavaScriptQuotes: Leave +JavaScriptWrapImports: true +KeepEmptyLinesAtTheStartOfBlocks: true +MacroBlockBegin: '' +MacroBlockEnd: '' +MaxEmptyLinesToKeep: 2 +NamespaceIndentation: None +ObjCBinPackProtocolList: Auto +ObjCBlockIndentWidth: 2 +ObjCSpaceAfterProperty: false +ObjCSpaceBeforeProtocolList: true +PenaltyBreakAssignment: 2 +PenaltyBreakBeforeFirstCallParameter: 19 +PenaltyBreakComment: 300 +PenaltyBreakFirstLessLess: 120 +PenaltyBreakString: 1000 +PenaltyBreakTemplateDeclaration: 10 +PenaltyExcessCharacter: 1000000 +PenaltyReturnTypeOnItsOwnLine: 1000 +PointerAlignment: Right +ReflowComments: false +SortIncludes: true +SortUsingDeclarations: true +SpaceAfterCStyleCast: false +SpaceAfterLogicalNot: false +SpaceAfterTemplateKeyword: true +SpaceBeforeAssignmentOperators: true +SpaceBeforeCpp11BracedList: false +SpaceBeforeCtorInitializerColon: true +SpaceBeforeInheritanceColon: true +SpaceBeforeParens: ControlStatements +SpaceBeforeRangeBasedForLoopColon: true +SpaceInEmptyBlock: false +SpaceInEmptyParentheses: false +SpacesBeforeTrailingComments: 1 +SpacesInAngles: false +SpacesInConditionalStatement: false +SpacesInContainerLiterals: true +SpacesInCStyleCastParentheses: false +SpacesInParentheses: false +SpacesInSquareBrackets: false +SpaceBeforeSquareBrackets: false +Standard: Latest +StatementMacros: + - Q_UNUSED + - QT_REQUIRE_VERSION +TabWidth: 4 +UseCRLF: false +UseTab: Never +... diff --git a/.clang-tidy b/.clang-tidy new file mode 100644 index 0000000..b17808b --- /dev/null +++ b/.clang-tidy @@ -0,0 +1,9 @@ +--- +Checks: 'clang-analyzer-*,cppcoreguidelines-*,modernize-*,bugprone-*,performance-*,readability-*,readability-non-const-parameter,misc-const-correctness,misc-use-anonymous-namespace,google-explicit-constructor,-modernize-use-trailing-return-type,-bugprone-exception-escape,-cppcoreguidelines-pro-bounds-constant-array-index,-cppcoreguidelines-avoid-magic-numbers,-bugprone-easily-swappable-parameters,-cppcoreguidelines-non-private-member-variables-in-classes' +WarningsAsErrors: '' +HeaderFilterRegex: '' +CheckOptions: + - key: readability-magic-numbers.IgnoredFloatingPointValues + value: '0.0;1.0;100.0;' + - key: readability-magic-numbers.IgnoredIntegerValues + value: '0;1;2;3;4;5;6;7;8;9;' diff --git a/.cmake-format.yaml b/.cmake-format.yaml new file mode 100644 index 0000000..f5d8dc3 --- /dev/null +++ b/.cmake-format.yaml @@ -0,0 +1,245 @@ +_help_parse: Options affecting listfile parsing +parse: + _help_additional_commands: + - Specify structure for custom cmake functions + additional_commands: + foo: + flags: + - BAR + - BAZ + kwargs: + HEADERS: '*' + SOURCES: '*' + DEPENDS: '*' + _help_override_spec: + - Override configurations per-command where available + override_spec: {} + _help_vartags: + - Specify variable tags. + vartags: [] + _help_proptags: + - Specify property tags. + proptags: [] +_help_format: Options affecting formatting. +format: + _help_disable: + - Disable formatting entirely, making cmake-format a no-op + disable: false + _help_line_width: + - How wide to allow formatted cmake files + line_width: 80 + _help_tab_size: + - How many spaces to tab for indent + tab_size: 4 + _help_use_tabchars: + - If true, lines are indented using tab characters (utf-8 + - 0x09) instead of <tab_size> space characters (utf-8 0x20). + - In cases where the layout would require a fractional tab + - character, the behavior of the fractional indentation is + - governed by <fractional_tab_policy> + use_tabchars: false + _help_fractional_tab_policy: + - If <use_tabchars> is True, then the value of this variable + - indicates how fractional indentions are handled during + - whitespace replacement. If set to 'use-space', fractional + - indentation is left as spaces (utf-8 0x20). If set to + - '`round-up` fractional indentation is replaced with a single' + - tab character (utf-8 0x09) effectively shifting the column + - to the next tabstop + fractional_tab_policy: use-space + _help_max_subgroups_hwrap: + - If an argument group contains more than this many sub-groups + - (parg or kwarg groups) then force it to a vertical layout. + max_subgroups_hwrap: 2 + _help_max_pargs_hwrap: + - If a positional argument group contains more than this many + - arguments, then force it to a vertical layout. + max_pargs_hwrap: 3 + _help_max_rows_cmdline: + - If a cmdline positional group consumes more than this many + - lines without nesting, then invalidate the layout (and nest) + max_rows_cmdline: 2 + _help_separate_ctrl_name_with_space: + - If true, separate flow control names from their parentheses + - with a space + separate_ctrl_name_with_space: false + _help_separate_fn_name_with_space: + - If true, separate function names from parentheses with a + - space + separate_fn_name_with_space: false + _help_dangle_parens: + - If a statement is wrapped to more than one line, than dangle + - the closing parenthesis on its own line. + dangle_parens: false + _help_dangle_align: + - If the trailing parenthesis must be 'dangled' on its on + - 'line, then align it to this reference: `prefix`: the start' + - 'of the statement, `prefix-indent`: the start of the' + - 'statement, plus one indentation level, `child`: align to' + - the column of the arguments + dangle_align: prefix + _help_min_prefix_chars: + - If the statement spelling length (including space and + - parenthesis) is smaller than this amount, then force reject + - nested layouts. + min_prefix_chars: 4 + _help_max_prefix_chars: + - If the statement spelling length (including space and + - parenthesis) is larger than the tab width by more than this + - amount, then force reject un-nested layouts. + max_prefix_chars: 10 + _help_max_lines_hwrap: + - If a candidate layout is wrapped horizontally but it exceeds + - this many lines, then reject the layout. + max_lines_hwrap: 1 + _help_line_ending: + - What style line endings to use in the output. + line_ending: unix + _help_command_case: + - Format command names consistently as 'lower' or 'upper' case + command_case: canonical + _help_keyword_case: + - Format keywords consistently as 'lower' or 'upper' case + keyword_case: unchanged + _help_always_wrap: + - A list of command names which should always be wrapped + always_wrap: [] + _help_enable_sort: + - If true, the argument lists which are known to be sortable + - will be sorted lexicographicall + enable_sort: true + _help_autosort: + - If true, the parsers may infer whether or not an argument + - list is sortable (without annotation). + autosort: false + _help_require_valid_layout: + - By default, if cmake-format cannot successfully fit + - everything into the desired linewidth it will apply the + - last, most agressive attempt that it made. If this flag is + - True, however, cmake-format will print error, exit with non- + - zero status code, and write-out nothing + require_valid_layout: false + _help_layout_passes: + - A dictionary mapping layout nodes to a list of wrap + - decisions. See the documentation for more information. + layout_passes: {} +_help_markup: Options affecting comment reflow and formatting. +markup: + _help_bullet_char: + - What character to use for bulleted lists + bullet_char: '*' + _help_enum_char: + - What character to use as punctuation after numerals in an + - enumerated list + enum_char: . + _help_first_comment_is_literal: + - If comment markup is enabled, don't reflow the first comment + - block in each listfile. Use this to preserve formatting of + - your copyright/license statements. + first_comment_is_literal: true + _help_literal_comment_pattern: + - If comment markup is enabled, don't reflow any comment block + - which matches this (regex) pattern. Default is `None` + - (disabled). + literal_comment_pattern: .* + _help_fence_pattern: + - Regular expression to match preformat fences in comments + - default= ``r'^\s*([`~]{3}[`~]*)(.*)$'`` + fence_pattern: ^\s*([`~]{3}[`~]*)(.*)$ + _help_ruler_pattern: + - Regular expression to match rulers in comments default= + - '``r''^\s*[^\w\s]{3}.*[^\w\s]{3}$''``' + ruler_pattern: ^\s*[^\w\s]{3}.*[^\w\s]{3}$ + _help_explicit_trailing_pattern: + - If a comment line matches starts with this pattern then it + - is explicitly a trailing comment for the preceeding + - argument. Default is '#<' + explicit_trailing_pattern: '#<' + _help_hashruler_min_length: + - If a comment line starts with at least this many consecutive + - hash characters, then don't lstrip() them off. This allows + - for lazy hash rulers where the first hash char is not + - separated by space + hashruler_min_length: 10 + _help_canonicalize_hashrulers: + - If true, then insert a space between the first hash char and + - remaining hash chars in a hash ruler, and normalize its + - length to fill the column + canonicalize_hashrulers: true + _help_enable_markup: + - enable comment markup parsing and reflow + enable_markup: true +_help_lint: Options affecting the linter +lint: + _help_disabled_codes: + - a list of lint codes to disable + disabled_codes: [] + _help_function_pattern: + - regular expression pattern describing valid function names + function_pattern: '[0-9a-z_]+' + _help_macro_pattern: + - regular expression pattern describing valid macro names + macro_pattern: '[0-9A-Z_]+' + _help_global_var_pattern: + - regular expression pattern describing valid names for + - variables with global (cache) scope + global_var_pattern: '[A-Z][0-9A-Z_]+' + _help_internal_var_pattern: + - regular expression pattern describing valid names for + - variables with global scope (but internal semantic) + internal_var_pattern: _[A-Z][0-9A-Z_]+ + _help_local_var_pattern: + - regular expression pattern describing valid names for + - variables with local scope + local_var_pattern: '[a-z][a-z0-9_]+' + _help_private_var_pattern: + - regular expression pattern describing valid names for + - privatedirectory variables + private_var_pattern: _[0-9a-z_]+ + _help_public_var_pattern: + - regular expression pattern describing valid names for public + - directory variables + public_var_pattern: '[A-Z][0-9A-Z_]+' + _help_argument_var_pattern: + - regular expression pattern describing valid names for + - function/macro arguments and loop variables. + argument_var_pattern: '[a-z][a-z0-9_]+' + _help_keyword_pattern: + - regular expression pattern describing valid names for + - keywords used in functions or macros + keyword_pattern: '[A-Z][0-9A-Z_]+' + _help_max_conditionals_custom_parser: + - In the heuristic for C0201, how many conditionals to match + - within a loop in before considering the loop a parser. + max_conditionals_custom_parser: 2 + _help_min_statement_spacing: + - Require at least this many newlines between statements + min_statement_spacing: 1 + _help_max_statement_spacing: + - Require no more than this many newlines between statements + max_statement_spacing: 2 + max_returns: 6 + max_branches: 12 + max_arguments: 5 + max_localvars: 15 + max_statements: 50 +_help_encode: Options affecting file encoding +encode: + _help_emit_byteorder_mark: + - If true, emit the unicode byte-order mark (BOM) at the start + - of the file + emit_byteorder_mark: false + _help_input_encoding: + - Specify the encoding of the input file. Defaults to utf-8 + input_encoding: utf-8 + _help_output_encoding: + - Specify the encoding of the output file. Defaults to utf-8. + - Note that cmake only claims to support utf-8 so be careful + - when using anything else + output_encoding: utf-8 +_help_misc: Miscellaneous configurations options. +misc: + _help_per_command: + - A dictionary containing any per-command configuration + - overrides. Currently only `command_case` is supported. + per_command: {} diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..7fc84ba --- /dev/null +++ b/.editorconfig @@ -0,0 +1,17 @@ +# EditorConfig is awesome: http://EditorConfig.org + +root = true + +[*] +indent_style = space +indent_size = 4 +trim_trailing_whitespace = true +insert_final_newline = true +end_of_line = lf + +[*.md] +trim_trailing_whitespace = false + +[Makefile] +indent_style = tab +trim_trailing_whitespace = false diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..c9a5f2b --- /dev/null +++ b/.gitattributes @@ -0,0 +1,11 @@ +# Set the default behavior for all files. +* text=auto eol=lf + +# Normalized and converts to native line endings on checkout. +*.c text +*.cc text +*.cxx +*.cpp text +*.h text +*.hxx text +*.hpp text diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml new file mode 100644 index 0000000..b995bfe --- /dev/null +++ b/.pre-commit-config.yaml @@ -0,0 +1,16 @@ +fail_fast: false +repos: +- repo: https://github.com/pre-commit/pre-commit-hooks + rev: v4.4.0 + hooks: + - id: check-yaml + - id: check-json + exclude: .vscode + - id: end-of-file-fixer + - id: trailing-whitespace + +- repo: https://github.com/pre-commit/mirrors-clang-format + rev: 'v16.0.3' + hooks: + - id: clang-format + exclude_types: [javascript, json] diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..03288fd --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,218 @@ +{ + "editor.tabSize": 4, + "editor.rulers": [ + 120 + ], + "editor.renderWhitespace": "trailing", + "editor.suggestSelection": "first", + "editor.formatOnSave": true, + "editor.defaultFormatter": "esbenp.prettier-vscode", + "editor.stickyScroll.enabled": false, + "editor.bracketPairColorization.enabled": false, + "editor.cursorSmoothCaretAnimation": "on", + "editor.suggest.preview": true, + "terminal.integrated.defaultProfile.windows": "Command Prompt", + "debug.onTaskErrors": "debugAnyway", + "explorer.compactFolders": false, + "explorer.confirmDragAndDrop": false, + "explorer.confirmDelete": false, + "explorer.copyRelativePathSeparator": "/", + "files.autoSave": "onFocusChange", + "files.exclude": { + "node_modules/**/*": true, + "**/.classpath": true, + "**/.project": true, + "**/.settings": true, + "**/.factorypath": true + }, + "files.associations": { + ".clang*": "yaml", + "*.hpp.in": "cpp", + "*.in": "cpp" + }, + "files.insertFinalNewline": true, + "files.trimFinalNewlines": true, + "files.trimTrailingWhitespace": true, + "workbench.startupEditor": "none", + "workbench.editorAssociations": { + "*.md": "vscode.markdown.preview.editor", + "*.svg": "svgPreviewer.customEditor" + }, + "workbench.colorTheme": "Default Dark+", + "git.enableSmartCommit": true, + "git.autofetch": true, + "git.confirmSync": false, + "git.openRepositoryInParentFolders": "always", + "prettier.tabWidth": 4, + "prettier.singleQuote": true, + "prettier.jsxSingleQuote": true, + "prettier.trailingComma": "all", + "prettier.useEditorConfig": true, + "prettier.bracketSpacing": false, + "markdown.validate.enabled": true, + "[markdown]": { + "files.trimTrailingWhitespace": false, + "editor.formatOnSave": false, + "editor.defaultFormatter": "yzhang.markdown-all-in-one", + "editor.wordWrap": "wordWrapColumn", + "editor.wordWrapColumn": 120 + }, + "[yaml]": { + "editor.formatOnSave": false, + "editor.defaultFormatter": "redhat.vscode-yaml", + "editor.wordWrap": "wordWrapColumn", + "editor.wordWrapColumn": 120 + }, + "[json]": { + "editor.formatOnSave": false, + "editor.defaultFormatter": "vscode.json-language-features" + }, + "[jsonc]": { + "editor.formatOnSave": false + }, + "[plaintext]": { + "editor.wordWrap": "wordWrapColumn", + "editor.wordWrapColumn": 120 + }, + "[toml]": { + "editor.wordWrap": "wordWrapColumn", + "editor.wordWrapColumn": 120 + }, + "better-comments.tags": [ + { + "tag": "XXX", + "color": "#F8C471" + }, + { + "tag": "WARN", + "color": "#FF6961" + }, + { + "tag": "NOTE", + "color": "#3498DB" + }, + { + "tag": "TODO", + "color": "#77C3EC" + } + ], + "vsintellicode.modify.editor.suggestSelection": "automaticallyOverrodeDefaultValue", + "codesnap.showWindowControls": false, + "codesnap.shutterAction": "copy", + "Workspace_Formatter.excludePattern": [ + "**/build", + "**/.*", + "**/.vscode", + "**/html" + ], + "Workspace_Formatter.includePattern": [ + "*.c", + "*.h", + "*.cc", + "*.hh", + "*.cpp", + "*.hpp" + ], + "svg.preview.autoOpen": true, + "remote.WSL.fileWatcher.polling": true, + "errorLens.delay": 1000, + "errorLens.enabledDiagnosticLevels": [ + "error", + "warning" + ], + "errorLens.enabled": false, + "C_Cpp.clang_format_sortIncludes": true, + "C_Cpp.vcFormat.indent.preserveComments": true, + "C_Cpp.vcFormat.indent.namespaceContents": false, + "C_Cpp.vcFormat.indent.caseContentsWhenBlock": true, + "C_Cpp.vcFormat.space.pointerReferenceAlignment": "right", + "C_Cpp.default.browse.limitSymbolsToIncludedHeaders": false, + "C_Cpp.default.cppStandard": "c++20", + "C_Cpp.default.cStandard": "c11", + "C_Cpp.formatting": "clangFormat", + "[c]": { + "editor.formatOnSave": false, + "editor.defaultFormatter": "ms-vscode.cpptools" + }, + "[cpp]": { + "editor.formatOnSave": false, + "editor.defaultFormatter": "ms-vscode.cpptools" + }, + "[cuda-cpp]": { + "editor.defaultFormatter": "ms-vscode.cpptools" + }, + "cmake.configureOnOpen": false, + "cmake.autoSelectActiveFolder": false, + "cmake.configureOnEdit": false, + "[cmake]": { + "editor.formatOnSave": false, + "editor.defaultFormatter": "cheshirekow.cmake-format" + }, + "cmake.options.statusBarVisibility": "visible", + "doxdocgen.file.fileTemplate": "@file {name}", + "doxdocgen.cpp.tparamTemplate": "@tparam {param} ", + "doxdocgen.generic.briefTemplate": "@brief {text}", + "doxdocgen.generic.boolReturnsTrueFalse": false, + "doxdocgen.generic.paramTemplate": "@param {param} ", + "doxdocgen.generic.returnTemplate": "@return", + "doxdocgen.generic.includeTypeAtReturn": false, + "C_Cpp.codeAnalysis.clangTidy.enabled": false, + "C_Cpp.configurationWarnings": "disabled", + "C_Cpp_Runner.cppStandard": "c++20", + "C_Cpp_Runner.cStandard": "c11", + "C_Cpp_Runner.enableWarnings": true, + "C_Cpp_Runner.warningsAsError": false, + "C_Cpp_Runner.cCompilerPath": "gcc", + "C_Cpp_Runner.cppCompilerPath": "g++", + "C_Cpp_Runner.debuggerPath": "gdb", + "C_Cpp_Runner.useMsvc": false, + "C_Cpp_Runner.warnings": [ + "-Wall", + "-Wextra", + "-Wpedantic", + "-Wshadow", + "-Wformat=2", + "-Wcast-align", + "-Wconversion", + "-Wsign-conversion", + "-Wnull-dereference" + ], + "C_Cpp_Runner.msvcWarnings": [ + "/W4", + "/permissive-", + "/w14242", + "/w14287", + "/w14296", + "/w14311", + "/w14826", + "/w44062", + "/w44242", + "/w14905", + "/w14906", + "/w14263", + "/w44265", + "/w14928" + ], + "C_Cpp_Runner.compilerArgs": [], + "C_Cpp_Runner.linkerArgs": [], + "C_Cpp_Runner.includePaths": [], + "C_Cpp_Runner.includeSearch": [ + "*", + "**/*" + ], + "C_Cpp_Runner.excludeSearch": [ + "**/build", + "**/build/**", + "**/.*", + "**/.*/**", + "**/.vscode", + "**/.vscode/**" + ], + "C_Cpp_Runner.useAddressSanitizer": false, + "C_Cpp_Runner.useUndefinedSanitizer": false, + "C_Cpp_Runner.useLeakSanitizer": false, + "C_Cpp_Runner.showCompilationTime": false, + "C_Cpp_Runner.useLinkTimeOptimization": false, + "C_Cpp_Runner.msvcSecureNoWarnings": false, + "C_Cpp_Runner.msvcBatchPath": "" +} \ No newline at end of file diff --git a/CMakeLists.txt b/CMakeLists.txt index fc6d1af..fc8afab 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,10 +1,14 @@ cmake_minimum_required(VERSION 2.8.12) -project( kmozillahelper ) +project(kmozillahelper) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11") -find_package(ECM 1.0.0 REQUIRED NO_MODULE) +find_package( + ECM + 1.0.0 + REQUIRED + NO_MODULE) set(CMAKE_MODULE_PATH ${ECM_MODULE_PATH} ${ECM_KDE_MODULE_DIR}) @@ -13,11 +17,21 @@ include(KDECMakeSettings) include(KDECompilerSettings) include(FeatureSummary) -find_package(KF5 REQUIRED COMPONENTS Notifications KIO WindowSystem I18n) +find_package( + KF5 REQUIRED + COMPONENTS Notifications + KIO + WindowSystem + I18n) add_executable(kmozillahelper main.cpp) -target_link_libraries(kmozillahelper KF5::I18n KF5::KIOWidgets KF5::Notifications KF5::WindowSystem) +target_link_libraries( + kmozillahelper + KF5::I18n + KF5::KIOWidgets + KF5::Notifications + KF5::WindowSystem) install(TARGETS kmozillahelper DESTINATION ${CMAKE_INSTALL_PREFIX}/lib/mozilla/) install(FILES kmozillahelper.notifyrc DESTINATION ${KNOTIFYRC_INSTALL_DIR}) diff --git a/main.cpp b/main.cpp index 21ac5ae..25b187e 100644 --- a/main.cpp +++ b/main.cpp @@ -30,25 +30,25 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. #include <iostream> +#include <QWindow> #include <QtCore/QCommandLineParser> -#include <QtCore/QMimeDatabase> #include <QtCore/QHash> +#include <QtCore/QMimeDatabase> #include <QtGui/QIcon> #include <QtWidgets/QApplication> #include <QtWidgets/QFileDialog> -#include <QWindow> #include <KConfigCore/KConfigGroup> #include <KConfigCore/KSharedConfig> #include <KCoreAddons/KAboutData> -#include <KCoreAddons/KShell> #include <KCoreAddons/KProcess> +#include <KCoreAddons/KShell> #include <KI18n/KLocalizedString> +#include <KIO/OpenUrlJob> #include <KIOCore/KProtocolManager> #include <KIOCore/KRecentDocument> #include <KIOWidgets/KOpenWithDialog> #include <KIOWidgets/KRun> -#include <KIO/OpenUrlJob> #include <KNotifications/KNotification> #include <KService/KMimeTypeTrader> #include <KWindowSystem/KWindowSystem> @@ -58,7 +58,7 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. #define HELPER_VERSION 6 #define APP_HELPER_VERSION "5.0.6" -int main(int argc, char* argv[]) +int main(int argc, char *argv[]) { // Avoid getting started by the session manager qunsetenv("SESSION_MANAGER"); @@ -72,7 +72,7 @@ int main(int argc, char* argv[]) // Check whether we're called from Firefox or Thunderbird QString appname = i18n("Mozilla Firefox"); QString parent = QFile::symLinkTarget(QStringLiteral("/proc/%1/exe").arg(int(getppid()))); - if(parent.contains("thunderbird", Qt::CaseInsensitive)) + if (parent.contains("thunderbird", Qt::CaseInsensitive)) appname = i18n("Mozilla Thunderbird"); // This shows on file dialogs @@ -93,18 +93,15 @@ int main(int argc, char* argv[]) return app.exec(); } -Helper::Helper() - : notifier(STDIN_FILENO, QSocketNotifier::Read) - , arguments_read(false) +Helper::Helper() : notifier(STDIN_FILENO, QSocketNotifier::Read), arguments_read(false) { - connect(¬ifier, &QSocketNotifier::activated, - this, &Helper::readCommand); + connect(¬ifier, &QSocketNotifier::activated, this, &Helper::readCommand); } void Helper::readCommand() { QString command = readLine(); - if(!std::cin.good()) + if (!std::cin.good()) { #ifdef DEBUG_KDE std::cerr << "EOF, exiting." << std::endl; @@ -125,49 +122,49 @@ void Helper::readCommand() std::cerr << "COMMAND: " << command.toStdString() << std::endl; #endif bool status; - if(command == "CHECK") + if (command == "CHECK") status = handleCheck(); - else if(command == "GETPROXY") + else if (command == "GETPROXY") status = handleGetProxy(); - else if(command == "HANDLEREXISTS") + else if (command == "HANDLEREXISTS") status = handleHandlerExists(); - else if(command == "GETFROMEXTENSION") + else if (command == "GETFROMEXTENSION") status = handleGetFromExtension(); - else if(command == "GETFROMTYPE") + else if (command == "GETFROMTYPE") status = handleGetFromType(); - else if(command == "GETAPPDESCFORSCHEME") + else if (command == "GETAPPDESCFORSCHEME") status = handleGetAppDescForScheme(); - else if(command == "APPSDIALOG") + else if (command == "APPSDIALOG") status = handleAppsDialog(); - else if(command == "GETOPENFILENAME") + else if (command == "GETOPENFILENAME") status = handleGetOpenOrSaveX(false, false); - else if(command == "GETOPENURL") + else if (command == "GETOPENURL") status = handleGetOpenOrSaveX(true, false); - else if(command == "GETSAVEFILENAME") + else if (command == "GETSAVEFILENAME") status = handleGetOpenOrSaveX(false, true); - else if(command == "GETSAVEURL") + else if (command == "GETSAVEURL") status = handleGetOpenOrSaveX(true, true); - else if(command == "GETDIRECTORYFILENAME") + else if (command == "GETDIRECTORYFILENAME") status = handleGetDirectoryX(false); - else if(command == "GETDIRECTORYURL") + else if (command == "GETDIRECTORYURL") status = handleGetDirectoryX(true); - else if(command == "OPEN") + else if (command == "OPEN") status = handleOpen(); - else if(command == "REVEAL") + else if (command == "REVEAL") status = handleReveal(); - else if(command == "RUN") + else if (command == "RUN") status = handleRun(); - else if(command == "GETDEFAULTFEEDREADER") + else if (command == "GETDEFAULTFEEDREADER") status = handleGetDefaultFeedReader(); - else if(command == "OPENMAIL") + else if (command == "OPENMAIL") status = handleOpenMail(); - else if(command == "OPENNEWS") + else if (command == "OPENNEWS") status = handleOpenNews(); - else if(command == "ISDEFAULTBROWSER") + else if (command == "ISDEFAULTBROWSER") status = handleIsDefaultBrowser(); - else if(command == "SETDEFAULTBROWSER") + else if (command == "SETDEFAULTBROWSER") status = handleSetDefaultBrowser(); - else if(command == "DOWNLOADFINISHED") + else if (command == "DOWNLOADFINISHED") status = handleDownloadFinished(); else { @@ -184,12 +181,12 @@ void Helper::readCommand() bool Helper::handleCheck() { - if(!readArguments(1)) + if (!readArguments(1)) return false; int version = getArgument().toInt(); // requested version - if(!allArgumentsUsed()) + if (!allArgumentsUsed()) return false; - if(version <= HELPER_VERSION) // we must have the exact requested version + if (version <= HELPER_VERSION) // we must have the exact requested version return true; std::cerr << "KDE helper version too old." << std::endl; return false; @@ -197,22 +194,24 @@ bool Helper::handleCheck() bool Helper::handleGetProxy() { - if(!readArguments(1)) + if (!readArguments(1)) return false; QUrl url = QUrl::fromUserInput(getArgument()); - if(!allArgumentsUsed()) + if (!allArgumentsUsed()) return false; QString proxy; KProtocolManager::slaveProtocol(url, proxy); - if(proxy.isEmpty() || proxy == "DIRECT") // TODO return DIRECT if empty? + if (proxy.isEmpty() || proxy == "DIRECT") // TODO return DIRECT if empty? { outputLine("DIRECT"); return true; } QUrl proxyurl = QUrl::fromUserInput(proxy); - if(proxyurl.isValid()) + if (proxyurl.isValid()) { // firefox wants this format - outputLine("PROXY" " " + proxyurl.host() + ":" + QString::number(proxyurl.port())); + outputLine("PROXY" + " " + + proxyurl.host() + ":" + QString::number(proxyurl.port())); // TODO there is also "SOCKS " type return true; } @@ -222,19 +221,19 @@ bool Helper::handleGetProxy() bool Helper::handleHandlerExists() { // Cache protocols types to avoid causing Thunderbird to hang (https://bugzilla.suse.com/show_bug.cgi?id=1037806). - static QHash<QString,bool> known_protocols; + static QHash<QString, bool> known_protocols; - if(!readArguments(1)) + if (!readArguments(1)) return false; QString protocol = getArgument(); - if(!allArgumentsUsed()) + if (!allArgumentsUsed()) return false; auto it(known_protocols.find(protocol)); - if(it == known_protocols.end()) + if (it == known_protocols.end()) it = known_protocols.insert(protocol, KProtocolInfo::isHelperProtocol(protocol)); - if(*it) + if (*it) return true; return KMimeTypeTrader::self()->preferredService(QLatin1String("x-scheme-handler/") + protocol) != nullptr; @@ -242,16 +241,16 @@ bool Helper::handleHandlerExists() bool Helper::handleGetFromExtension() { - if(!readArguments(1)) + if (!readArguments(1)) return false; QString ext = getArgument(); - if(!allArgumentsUsed()) + if (!allArgumentsUsed()) return false; - if(!ext.isEmpty()) + if (!ext.isEmpty()) { QList<QMimeType> mimeList = QMimeDatabase().mimeTypesForFileName("foo." + ext); for (const QMimeType &mime : mimeList) - if(mime.isValid()) + if (mime.isValid()) return writeMimeInfo(mime); } return false; @@ -259,17 +258,17 @@ bool Helper::handleGetFromExtension() bool Helper::handleGetFromType() { - if(!readArguments(1)) + if (!readArguments(1)) return false; QString type = getArgument(); - if(!allArgumentsUsed()) + if (!allArgumentsUsed()) return false; QMimeType mime = QMimeDatabase().mimeTypeForName(type); - if(mime.isValid()) + if (mime.isValid()) return writeMimeInfo(mime); // firefox also asks for protocol handlers using getfromtype QString app = getAppForProtocol(type); - if(!app.isEmpty()) + if (!app.isEmpty()) { outputLine(type); outputLine(type); // TODO probably no way to find a good description @@ -282,7 +281,7 @@ bool Helper::handleGetFromType() bool Helper::writeMimeInfo(QMimeType mime) { KService::Ptr service = KMimeTypeTrader::self()->preferredService(mime.name()); - if(service) + if (service) { outputLine(mime.name()); outputLine(mime.comment()); @@ -294,13 +293,13 @@ bool Helper::writeMimeInfo(QMimeType mime) bool Helper::handleGetAppDescForScheme() { - if(!readArguments(1)) + if (!readArguments(1)) return false; QString scheme = getArgument(); - if(!allArgumentsUsed()) + if (!allArgumentsUsed()) return false; QString app = getAppForProtocol(scheme); - if(!app.isEmpty()) + if (!app.isEmpty()) { outputLine(app); return true; @@ -310,37 +309,37 @@ bool Helper::handleGetAppDescForScheme() bool Helper::handleAppsDialog() { - if(!readArguments(1)) + if (!readArguments(1)) return false; QString title = getArgument(); long wid = getArgumentParent(); - if(!allArgumentsUsed()) + if (!allArgumentsUsed()) return false; KOpenWithDialog dialog(NULL); - if(!title.isEmpty()) + if (!title.isEmpty()) dialog.setWindowTitle(title); dialog.hideNoCloseOnExit(); dialog.hideRunInTerminal(); // TODO - if(wid != 0) + if (wid != 0) { dialog.setAttribute(Qt::WA_NativeWindow, true); QWindow *subWindow = dialog.windowHandle(); - if(subWindow) + if (subWindow) KWindowSystem::setMainWindow(subWindow, wid); } - if(dialog.exec()) + if (dialog.exec()) { KService::Ptr service = dialog.service(); QString command; - if(service) + if (service) command = service->exec(); - else if(!dialog.text().isEmpty()) + else if (!dialog.text().isEmpty()) command = dialog.text(); else return false; command = command.split(" ").first(); // only the actual command command = QStandardPaths::findExecutable(command); - if(command.isEmpty()) + if (command.isEmpty()) return false; outputLine(QUrl::fromUserInput(command).url()); return true; @@ -370,7 +369,7 @@ QStringList Helper::convertToNameFilters(const QString &input) bool Helper::handleGetOpenOrSaveX(bool url, bool save) { - if(!readArguments(4)) + if (!readArguments(4)) return false; QUrl defaultPath = QUrl::fromLocalFile(getArgument()); // Use dialog.nameFilters() instead of filtersParsed as setNameFilters does some syntax changes @@ -379,10 +378,10 @@ bool Helper::handleGetOpenOrSaveX(bool url, bool save) QString title = getArgument(); bool multiple = save ? false : isArgument("MULTIPLE"); this->wid = getArgumentParent(); - if(!allArgumentsUsed()) + if (!allArgumentsUsed()) return false; - if(title.isEmpty()) + if (title.isEmpty()) title = save ? i18n("Save") : i18n("Open"); QFileDialog dialog(nullptr, title, defaultPath.path()); @@ -392,31 +391,31 @@ bool Helper::handleGetOpenOrSaveX(bool url, bool save) dialog.setOption(QFileDialog::DontConfirmOverwrite, false); dialog.setAcceptMode(save ? QFileDialog::AcceptSave : QFileDialog::AcceptOpen); - if(save) + if (save) dialog.setFileMode((QFileDialog::AnyFile)); else dialog.setFileMode(multiple ? QFileDialog::ExistingFiles : QFileDialog::ExistingFile); - if(selectFilter >= 0 && selectFilter >= dialog.nameFilters().size()) + if (selectFilter >= 0 && selectFilter >= dialog.nameFilters().size()) dialog.selectNameFilter(dialog.nameFilters().at(selectFilter)); - // If url == false only allow local files. Impossible to do with Qt < 5.6... -#if(QT_VERSION >= QT_VERSION_CHECK(5, 6, 0)) - if(url == false) + // If url == false only allow local files. Impossible to do with Qt < 5.6... +#if (QT_VERSION >= QT_VERSION_CHECK(5, 6, 0)) + if (url == false) dialog.setSupportedSchemes(QStringList(QStringLiteral("file"))); #endif // Run dialog - if(dialog.exec() != QDialog::Accepted) + if (dialog.exec() != QDialog::Accepted) return false; int usedFilter = dialog.nameFilters().indexOf(dialog.selectedNameFilter()); - if(url) + if (url) { QList<QUrl> result = dialog.selectedUrls(); result.removeAll(QUrl()); - if(!result.isEmpty()) + if (!result.isEmpty()) { outputLine(QStringLiteral("%0").arg(usedFilter)); for (const QUrl &url : result) @@ -428,7 +427,7 @@ bool Helper::handleGetOpenOrSaveX(bool url, bool save) { QStringList result = dialog.selectedFiles(); result.removeAll(QString()); - if(!result.isEmpty()) + if (!result.isEmpty()) { outputLine(QStringLiteral("%0").arg(usedFilter)); for (const QString &str : result) @@ -441,18 +440,18 @@ bool Helper::handleGetOpenOrSaveX(bool url, bool save) bool Helper::handleGetDirectoryX(bool url) { - if(!readArguments(2)) + if (!readArguments(2)) return false; QString startDir = getArgument(); QString title = getArgument(); this->wid = getArgumentParent(); - if(!allArgumentsUsed()) + if (!allArgumentsUsed()) return false; - if(url) + if (url) { QUrl result = QFileDialog::getExistingDirectoryUrl(nullptr, title, startDir); - if(result.isValid()) + if (result.isValid()) { outputLine(result.url()); return true; @@ -461,7 +460,7 @@ bool Helper::handleGetDirectoryX(bool url) else { QString result = QFileDialog::getExistingDirectory(nullptr, title, startDir); - if(!result.isEmpty()) + if (!result.isEmpty()) { outputLine(result); return true; @@ -472,13 +471,13 @@ bool Helper::handleGetDirectoryX(bool url) bool Helper::handleOpen() { - if(!readArguments(1)) + if (!readArguments(1)) return false; QUrl url = QUrl::fromUserInput(getArgument()); QString mime; - if(isArgument("MIMETYPE")) + if (isArgument("MIMETYPE")) mime = getArgument(); - if(!allArgumentsUsed()) + if (!allArgumentsUsed()) return false; auto ouj = new KIO::OpenUrlJob(url, mime); @@ -488,47 +487,47 @@ bool Helper::handleOpen() bool Helper::handleReveal() { - if(!readArguments(1)) + if (!readArguments(1)) return false; QString path = getArgument(); - if(!allArgumentsUsed()) + if (!allArgumentsUsed()) return false; const KService::List apps = KMimeTypeTrader::self()->query("inode/directory", "Application"); - if(apps.size() != 0) + if (apps.size() != 0) { QString command = apps.at(0)->exec().split(" ").first(); // only the actual command - if(command == "dolphin" || command == "konqueror") + if (command == "dolphin" || command == "konqueror") { command = QStandardPaths::findExecutable(command); - if(command.isEmpty()) + if (command.isEmpty()) return false; return KProcess::startDetached(command, QStringList() << "--select" << path); } } QFileInfo info(path); QString dir = info.dir().path(); - (void) new KRun(QUrl::fromLocalFile(dir), NULL); // TODO parent - return true; // TODO check for errors? + (void)new KRun(QUrl::fromLocalFile(dir), NULL); // TODO parent + return true; // TODO check for errors? } bool Helper::handleRun() { - if(!readArguments(2)) + if (!readArguments(2)) return false; QString app = getArgument(); QString arg = getArgument(); - if(!allArgumentsUsed()) + if (!allArgumentsUsed()) return false; return KRun::runCommand(KShell::quoteArg(app) + " " + KShell::quoteArg(arg), NULL); // TODO parent, ASN } bool Helper::handleGetDefaultFeedReader() { - if(!readArguments(0)) + if (!readArguments(0)) return false; // firefox wants the full path QString reader = QStandardPaths::findExecutable("akregator"); // TODO there is no KDE setting for this - if(!reader.isEmpty()) + if (!reader.isEmpty()) { outputLine(reader); return true; @@ -538,22 +537,23 @@ bool Helper::handleGetDefaultFeedReader() bool Helper::handleOpenMail() { - if(!readArguments(0)) + if (!readArguments(0)) return false; // this is based on ktoolinvocation_x11.cpp, there is no API for this KConfig config("emaildefaults"); QString groupname = KConfigGroup(&config, "Defaults").readEntry("Profile", "Default"); KConfigGroup group(&config, QString("PROFILE_%1").arg(groupname)); QString command = group.readPathEntry("EmailClient", QString()); - if(command.isEmpty()) + if (command.isEmpty()) command = "kmail"; - if(group.readEntry("TerminalClient", false)) + if (group.readEntry("TerminalClient", false)) { - QString terminal = KConfigGroup(KSharedConfig::openConfig(), "General").readPathEntry("TerminalApplication", "konsole"); + QString terminal = + KConfigGroup(KSharedConfig::openConfig(), "General").readPathEntry("TerminalApplication", "konsole"); command = terminal + " -e " + command; } KService::Ptr mail = KService::serviceByDesktopName(command.split(" ").first()); - if(mail) + if (mail) { return KRun::runService(*mail, QList<QUrl>(), NULL); // TODO parent } @@ -562,10 +562,10 @@ bool Helper::handleOpenMail() bool Helper::handleOpenNews() { - if(!readArguments(0)) + if (!readArguments(0)) return false; KService::Ptr news = KService::serviceByDesktopName("knode"); // TODO there is no KDE setting for this - if(news) + if (news) { //KApplication::updateUserTimestamp(0); // TODO return KRun::runService(*news, QList<QUrl>(), NULL); // TODO parent @@ -575,25 +575,22 @@ bool Helper::handleOpenNews() bool Helper::handleIsDefaultBrowser() { - if(!readArguments(0)) + if (!readArguments(0)) return false; - QString browser = KConfigGroup(KSharedConfig::openConfig("kdeglobals"), "General") - .readEntry("BrowserApplication"); - return browser == "MozillaFirefox" || browser == "MozillaFirefox.desktop" - || browser == "!firefox" || browser == "!/usr/bin/firefox" - || browser == "firefox" || browser == "firefox.desktop"; + QString browser = KConfigGroup(KSharedConfig::openConfig("kdeglobals"), "General").readEntry("BrowserApplication"); + return browser == "MozillaFirefox" || browser == "MozillaFirefox.desktop" || browser == "!firefox" || + browser == "!/usr/bin/firefox" || browser == "firefox" || browser == "firefox.desktop"; } bool Helper::handleSetDefaultBrowser() { - if(!readArguments(1)) + if (!readArguments(1)) return false; bool alltypes = (getArgument() == "ALLTYPES"); - if(!allArgumentsUsed()) + if (!allArgumentsUsed()) return false; - KConfigGroup(KSharedConfig::openConfig("kdeglobals"), "General") - .writeEntry("BrowserApplication", "firefox"); - if(alltypes) + KConfigGroup(KSharedConfig::openConfig("kdeglobals"), "General").writeEntry("BrowserApplication", "firefox"); + if (alltypes) { // TODO there is no API for this and it is a bit complex } @@ -602,10 +599,10 @@ bool Helper::handleSetDefaultBrowser() bool Helper::handleDownloadFinished() { - if(!readArguments(1)) + if (!readArguments(1)) return false; QString download = getArgument(); - if(!allArgumentsUsed()) + if (!allArgumentsUsed()) return false; // TODO cheat a bit due to i18n freeze - the strings are in the .notifyrc file, // taken from KGet, but the notification itself needs the text too. @@ -616,10 +613,11 @@ bool Helper::handleDownloadFinished() return true; } -QString Helper::getAppForProtocol(const QString& protocol) +QString Helper::getAppForProtocol(const QString &protocol) { /* Inspired by kio's krun.cpp */ - const KService::Ptr service = KMimeTypeTrader::self()->preferredService(QLatin1String("x-scheme-handler/") + protocol); + const KService::Ptr service = + KMimeTypeTrader::self()->preferredService(QLatin1String("x-scheme-handler/") + protocol); if (service) return service->name(); @@ -630,34 +628,34 @@ QString Helper::getAppForProtocol(const QString& protocol) * So we need to query for the service to use and then find the .desktop * file for that application by comparing the Exec values. */ - if(!KProtocolInfo::isHelperProtocol(protocol)) + if (!KProtocolInfo::isHelperProtocol(protocol)) return {}; QString exec = KProtocolInfo::exec(protocol); - if(exec.isEmpty()) + if (exec.isEmpty()) return {}; - if(exec.contains(' ')) + if (exec.contains(' ')) exec = exec.split(' ').first(); // first part of command - if(KService::Ptr service = KService::serviceByDesktopName(exec)) + if (KService::Ptr service = KService::serviceByDesktopName(exec)) return service->name(); QString servicename; - foreach(KService::Ptr service, KService::allServices()) + foreach (KService::Ptr service, KService::allServices()) { QString exec2 = service->exec(); - if(exec2.contains(' ')) + if (exec2.contains(' ')) exec2 = exec2.split(' ').first(); // first part of command - if(exec == exec2) + if (exec == exec2) { servicename = service->name(); break; } } - if(servicename.isEmpty() && exec == "kmailservice") // kmailto is handled internally by kmailservice + if (servicename.isEmpty() && exec == "kmailservice") // kmailto is handled internally by kmailservice servicename = i18n("KDE"); return servicename; @@ -666,12 +664,14 @@ QString Helper::getAppForProtocol(const QString& protocol) QString Helper::readLine() { std::string line; - if(!std::getline(std::cin, line)) + if (!std::getline(std::cin, line)) return {}; QString qline = QString::fromStdString(line); qline.replace("\\n", "\n"); - qline.replace("\\" "\\", "\\"); + qline.replace("\\" + "\\", + "\\"); return qline; } @@ -681,14 +681,14 @@ QString Helper::readLine() * and setTransientParent here instead. */ bool Helper::eventFilter(QObject *obj, QEvent *ev) { - if(ev->type() == QEvent::Show && obj->inherits("QDialog")) + if (ev->type() == QEvent::Show && obj->inherits("QDialog")) { - QWidget *widget = static_cast<QWidget*>(obj); - if(wid != 0) + QWidget *widget = static_cast<QWidget *>(obj); + if (wid != 0) { widget->setAttribute(Qt::WA_NativeWindow, true); QWindow *subWindow = widget->windowHandle(); - if(subWindow) + if (subWindow) KWindowSystem::setMainWindow(subWindow, wid); } } @@ -698,9 +698,11 @@ bool Helper::eventFilter(QObject *obj, QEvent *ev) void Helper::outputLine(QString line, bool escape) { - if(escape) + if (escape) { - line.replace("\\", "\\" "\\"); + line.replace("\\", + "\\" + "\\"); line.replace("\n", "\\n"); } std::cout << line.toStdString() << std::endl; @@ -712,18 +714,18 @@ void Helper::outputLine(QString line, bool escape) bool Helper::readArguments(int mincount) { assert(arguments.isEmpty()); - for(;;) + for (;;) { QString line = readLine(); - if(!std::cin.good()) + if (!std::cin.good()) { arguments.clear(); return false; } - if(line == "\\E") + if (line == "\\E") { arguments_read = true; - if(arguments.count() >= mincount) + if (arguments.count() >= mincount) return true; std::cerr << "Not enough arguments for KDE helper." << std::endl; return false; @@ -738,9 +740,9 @@ QString Helper::getArgument() return arguments.takeFirst(); } -bool Helper::isArgument(const QString& argument) +bool Helper::isArgument(const QString &argument) { - if(!arguments.isEmpty() && arguments.first() == argument) + if (!arguments.isEmpty() && arguments.first() == argument) { arguments.removeFirst(); return true; @@ -752,7 +754,7 @@ bool Helper::allArgumentsUsed() { assert(arguments_read); arguments_read = false; - if(arguments.isEmpty()) + if (arguments.isEmpty()) return true; std::cerr << "Unused arguments for KDE helper:" << arguments.join(" ").toStdString() << std::endl; arguments.clear(); @@ -761,7 +763,7 @@ bool Helper::allArgumentsUsed() long Helper::getArgumentParent() { - if(isArgument("PARENT")) + if (isArgument("PARENT")) return getArgument().toLong(); return 0; } diff --git a/main.h b/main.h index 29482d7..f728337 100644 --- a/main.h +++ b/main.h @@ -32,6 +32,7 @@ class Helper : public QObject Q_OBJECT public: Helper(); + private: bool handleCheck(); bool handleGetProxy(); @@ -53,18 +54,20 @@ class Helper : public QObject bool handleDownloadFinished(); QStringList convertToNameFilters(const QString &input); bool writeMimeInfo(QMimeType mime); - QString getAppForProtocol(const QString& protocol); + QString getAppForProtocol(const QString &protocol); bool readArguments(int mincount); QString getArgument(); - bool isArgument(const QString& name); // also discards the line with it + bool isArgument(const QString &name); // also discards the line with it bool allArgumentsUsed(); long getArgumentParent(); void outputLine(QString line, bool escape = true); QString readLine(); + protected: virtual bool eventFilter(QObject *obj, QEvent *ev) override; private slots: void readCommand(); + private: QSocketNotifier notifier; QStringList arguments; diff --git a/tools/run-clang-format.py b/tools/run-clang-format.py new file mode 100644 index 0000000..1dea8ab --- /dev/null +++ b/tools/run-clang-format.py @@ -0,0 +1,408 @@ +#!/usr/bin/env python +"""A wrapper script around clang-format, suitable for linting multiple files +and to use for continuous integration. + +This is an alternative API for the clang-format command line. +It runs over multiple files and directories in parallel. +A diff output is produced and a sensible exit code is returned. + +""" + +from __future__ import print_function, unicode_literals + +import argparse +import codecs +import difflib +import fnmatch +import io +import errno +import multiprocessing +import os +import signal +import subprocess +import sys +import traceback + +from functools import partial + +try: + from subprocess import DEVNULL # py3k +except ImportError: + DEVNULL = open(os.devnull, "wb") + + +DEFAULT_EXTENSIONS = 'c,h,C,H,cpp,hpp,cc,hh,c++,h++,cxx,hxx' +DEFAULT_CLANG_FORMAT_IGNORE = '.clang-format-ignore' + + +class ExitStatus: + SUCCESS = 0 + DIFF = 1 + TROUBLE = 2 + +def excludes_from_file(ignore_file): + excludes = [] + try: + with io.open(ignore_file, 'r', encoding='utf-8') as f: + for line in f: + if line.startswith('#'): + # ignore comments + continue + pattern = line.rstrip() + if not pattern: + # allow empty lines + continue + excludes.append(pattern) + except EnvironmentError as e: + if e.errno != errno.ENOENT: + raise + return excludes + +def list_files(files, recursive=False, extensions=None, exclude=None): + if extensions is None: + extensions = [] + if exclude is None: + exclude = [] + + out = [] + for file in files: + if recursive and os.path.isdir(file): + for dirpath, dnames, fnames in os.walk(file): + fpaths = [os.path.join(dirpath, fname) for fname in fnames] + for pattern in exclude: + # os.walk() supports trimming down the dnames list + # by modifying it in-place, + # to avoid unnecessary directory listings. + dnames[:] = [ + x for x in dnames + if + not fnmatch.fnmatch(os.path.join(dirpath, x), pattern) + ] + fpaths = [ + x for x in fpaths if not fnmatch.fnmatch(x, pattern) + ] + for f in fpaths: + ext = os.path.splitext(f)[1][1:] + if ext in extensions: + out.append(f) + else: + out.append(file) + return out + + +def make_diff(file, original, reformatted): + return list( + difflib.unified_diff( + original, + reformatted, + fromfile='{}\t(original)'.format(file), + tofile='{}\t(reformatted)'.format(file), + n=3)) + + +class DiffError(Exception): + def __init__(self, message, errs=None): + super(DiffError, self).__init__(message) + self.errs = errs or [] + + +class UnexpectedError(Exception): + def __init__(self, message, exc=None): + super(UnexpectedError, self).__init__(message) + self.formatted_traceback = traceback.format_exc() + self.exc = exc + + +def run_clang_format_diff_wrapper(args, file): + try: + ret = run_clang_format_diff(args, file) + return ret + except DiffError: + raise + except Exception as e: + raise UnexpectedError('{}: {}: {}'.format(file, e.__class__.__name__, + e), e) + + +def run_clang_format_diff(args, file): + try: + with io.open(file, 'r', encoding='utf-8') as f: + original = f.readlines() + except IOError as exc: + raise DiffError(str(exc)) + + if args.in_place: + invocation = [args.clang_format_executable, '-i', file] + else: + invocation = [args.clang_format_executable, file] + + if args.style: + invocation.extend(['--style', args.style]) + + if args.dry_run: + print(" ".join(invocation)) + return [], [] + + # Use of utf-8 to decode the process output. + # + # Hopefully, this is the correct thing to do. + # + # It's done due to the following assumptions (which may be incorrect): + # - clang-format will returns the bytes read from the files as-is, + # without conversion, and it is already assumed that the files use utf-8. + # - if the diagnostics were internationalized, they would use utf-8: + # > Adding Translations to Clang + # > + # > Not possible yet! + # > Diagnostic strings should be written in UTF-8, + # > the client can translate to the relevant code page if needed. + # > Each translation completely replaces the format string + # > for the diagnostic. + # > -- http://clang.llvm.org/docs/InternalsManual.html#internals-diag-translation + # + # It's not pretty, due to Python 2 & 3 compatibility. + encoding_py3 = {} + if sys.version_info[0] >= 3: + encoding_py3['encoding'] = 'utf-8' + + try: + proc = subprocess.Popen( + invocation, + stdout=subprocess.PIPE, + stderr=subprocess.PIPE, + universal_newlines=True, + **encoding_py3) + except OSError as exc: + raise DiffError( + "Command '{}' failed to start: {}".format( + subprocess.list2cmdline(invocation), exc + ) + ) + proc_stdout = proc.stdout + proc_stderr = proc.stderr + if sys.version_info[0] < 3: + # make the pipes compatible with Python 3, + # reading lines should output unicode + encoding = 'utf-8' + proc_stdout = codecs.getreader(encoding)(proc_stdout) + proc_stderr = codecs.getreader(encoding)(proc_stderr) + # hopefully the stderr pipe won't get full and block the process + outs = list(proc_stdout.readlines()) + errs = list(proc_stderr.readlines()) + proc.wait() + if proc.returncode: + raise DiffError( + "Command '{}' returned non-zero exit status {}".format( + subprocess.list2cmdline(invocation), proc.returncode + ), + errs, + ) + if args.in_place: + return [], errs + return make_diff(file, original, outs), errs + + +def bold_red(s): + return '\x1b[1m\x1b[31m' + s + '\x1b[0m' + + +def colorize(diff_lines): + def bold(s): + return '\x1b[1m' + s + '\x1b[0m' + + def cyan(s): + return '\x1b[36m' + s + '\x1b[0m' + + def green(s): + return '\x1b[32m' + s + '\x1b[0m' + + def red(s): + return '\x1b[31m' + s + '\x1b[0m' + + for line in diff_lines: + if line[:4] in ['--- ', '+++ ']: + yield bold(line) + elif line.startswith('@@ '): + yield cyan(line) + elif line.startswith('+'): + yield green(line) + elif line.startswith('-'): + yield red(line) + else: + yield line + + +def print_diff(diff_lines, use_color): + if use_color: + diff_lines = colorize(diff_lines) + if sys.version_info[0] < 3: + sys.stdout.writelines((l.encode('utf-8') for l in diff_lines)) + else: + sys.stdout.writelines(diff_lines) + + +def print_trouble(prog, message, use_colors): + error_text = 'error:' + if use_colors: + error_text = bold_red(error_text) + print("{}: {} {}".format(prog, error_text, message), file=sys.stderr) + + +def main(): + parser = argparse.ArgumentParser(description=__doc__) + parser.add_argument( + '--clang-format-executable', + metavar='EXECUTABLE', + help='path to the clang-format executable', + default='clang-format') + parser.add_argument( + '--extensions', + help='comma separated list of file extensions (default: {})'.format( + DEFAULT_EXTENSIONS), + default=DEFAULT_EXTENSIONS) + parser.add_argument( + '-r', + '--recursive', + action='store_true', + help='run recursively over directories') + parser.add_argument( + '-d', + '--dry-run', + action='store_true', + help='just print the list of files') + parser.add_argument( + '-i', + '--in-place', + action='store_true', + help='format file instead of printing differences') + parser.add_argument('files', metavar='file', nargs='+') + parser.add_argument( + '-q', + '--quiet', + action='store_true', + help="disable output, useful for the exit code") + parser.add_argument( + '-j', + metavar='N', + type=int, + default=0, + help='run N clang-format jobs in parallel' + ' (default number of cpus + 1)') + parser.add_argument( + '--color', + default='auto', + choices=['auto', 'always', 'never'], + help='show colored diff (default: auto)') + parser.add_argument( + '-e', + '--exclude', + metavar='PATTERN', + action='append', + default=[], + help='exclude paths matching the given glob-like pattern(s)' + ' from recursive search') + parser.add_argument( + '--style', + help='formatting style to apply (LLVM, Google, Chromium, Mozilla, WebKit)') + + args = parser.parse_args() + + # use default signal handling, like diff return SIGINT value on ^C + # https://bugs.python.org/issue14229#msg156446 + signal.signal(signal.SIGINT, signal.SIG_DFL) + try: + signal.SIGPIPE + except AttributeError: + # compatibility, SIGPIPE does not exist on Windows + pass + else: + signal.signal(signal.SIGPIPE, signal.SIG_DFL) + + colored_stdout = False + colored_stderr = False + if args.color == 'always': + colored_stdout = True + colored_stderr = True + elif args.color == 'auto': + colored_stdout = sys.stdout.isatty() + colored_stderr = sys.stderr.isatty() + + version_invocation = [args.clang_format_executable, str("--version")] + try: + subprocess.check_call(version_invocation, stdout=DEVNULL) + except subprocess.CalledProcessError as e: + print_trouble(parser.prog, str(e), use_colors=colored_stderr) + return ExitStatus.TROUBLE + except OSError as e: + print_trouble( + parser.prog, + "Command '{}' failed to start: {}".format( + subprocess.list2cmdline(version_invocation), e + ), + use_colors=colored_stderr, + ) + return ExitStatus.TROUBLE + + retcode = ExitStatus.SUCCESS + + excludes = excludes_from_file(DEFAULT_CLANG_FORMAT_IGNORE) + excludes.extend(args.exclude) + + files = list_files( + args.files, + recursive=args.recursive, + exclude=excludes, + extensions=args.extensions.split(',')) + + if not files: + return + + njobs = args.j + if njobs == 0: + njobs = multiprocessing.cpu_count() + 1 + njobs = min(len(files), njobs) + + if njobs == 1: + # execute directly instead of in a pool, + # less overhead, simpler stacktraces + it = (run_clang_format_diff_wrapper(args, file) for file in files) + pool = None + else: + pool = multiprocessing.Pool(njobs) + it = pool.imap_unordered( + partial(run_clang_format_diff_wrapper, args), files) + pool.close() + while True: + try: + outs, errs = next(it) + except StopIteration: + break + except DiffError as e: + print_trouble(parser.prog, str(e), use_colors=colored_stderr) + retcode = ExitStatus.TROUBLE + sys.stderr.writelines(e.errs) + except UnexpectedError as e: + print_trouble(parser.prog, str(e), use_colors=colored_stderr) + sys.stderr.write(e.formatted_traceback) + retcode = ExitStatus.TROUBLE + # stop at the first unexpected error, + # something could be very wrong, + # don't process all files unnecessarily + if pool: + pool.terminate() + break + else: + sys.stderr.writelines(errs) + if outs == []: + continue + if not args.quiet: + print_diff(outs, use_color=colored_stdout) + if retcode == ExitStatus.SUCCESS: + retcode = ExitStatus.DIFF + if pool: + pool.join() + return retcode + + +if __name__ == '__main__': + sys.exit(main()) diff --git a/tools/run-clang-tidy.py b/tools/run-clang-tidy.py new file mode 100644 index 0000000..815c2ea --- /dev/null +++ b/tools/run-clang-tidy.py @@ -0,0 +1,493 @@ +#!/usr/bin/env python3 +# +# ===- run-clang-tidy.py - Parallel clang-tidy runner --------*- python -*--===# +# +# Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +# See https://llvm.org/LICENSE.txt for license information. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +# +# ===-----------------------------------------------------------------------===# +# FIXME: Integrate with clang-tidy-diff.py + + +""" +Parallel clang-tidy runner +========================== + +Runs clang-tidy over all files in a compilation database. Requires clang-tidy +and clang-apply-replacements in $PATH. + +Example invocations. +- Run clang-tidy on all files in the current working directory with a default + set of checks and show warnings in the cpp files and all project headers. + run-clang-tidy.py $PWD + +- Fix all header guards. + run-clang-tidy.py -fix -checks=-*,llvm-header-guard + +- Fix all header guards included from clang-tidy and header guards + for clang-tidy headers. + run-clang-tidy.py -fix -checks=-*,llvm-header-guard extra/clang-tidy \ + -header-filter=extra/clang-tidy + +Compilation database setup: +http://clang.llvm.org/docs/HowToSetupToolingForLLVM.html +""" + +from __future__ import print_function + +import argparse +import glob +import json +import multiprocessing +import os +import queue +import re +import shutil +import subprocess +import sys +import tempfile +import threading +import traceback + +try: + import yaml +except ImportError: + yaml = None + + +def strtobool(val): + """Convert a string representation of truth to a bool following LLVM's CLI argument parsing.""" + + val = val.lower() + if val in ["", "true", "1"]: + return True + elif val in ["false", "0"]: + return False + + # Return ArgumentTypeError so that argparse does not substitute its own error message + raise argparse.ArgumentTypeError( + "'{}' is invalid value for boolean argument! Try 0 or 1.".format(val) + ) + + +def find_compilation_database(path): + """Adjusts the directory until a compilation database is found.""" + result = os.path.realpath("./") + while not os.path.isfile(os.path.join(result, path)): + parent = os.path.dirname(result) + if result == parent: + print("Error: could not find compilation database!") + sys.exit(1) + result = parent + return result + + +def make_absolute(f, directory): + if os.path.isabs(f): + return f + return os.path.normpath(os.path.join(directory, f)) + + +def get_tidy_invocation( + f, + clang_tidy_binary, + checks, + tmpdir, + build_path, + header_filter, + allow_enabling_alpha_checkers, + extra_arg, + extra_arg_before, + quiet, + config_file_path, + config, + line_filter, + use_color, + plugins, +): + """Gets a command line for clang-tidy.""" + start = [clang_tidy_binary] + if allow_enabling_alpha_checkers: + start.append("-allow-enabling-analyzer-alpha-checkers") + if header_filter is not None: + start.append("-header-filter=" + header_filter) + if line_filter is not None: + start.append("-line-filter=" + line_filter) + if use_color is not None: + if use_color: + start.append("--use-color") + else: + start.append("--use-color=false") + if checks: + start.append("-checks=" + checks) + if tmpdir is not None: + start.append("-export-fixes") + # Get a temporary file. We immediately close the handle so clang-tidy can + # overwrite it. + (handle, name) = tempfile.mkstemp(suffix=".yaml", dir=tmpdir) + os.close(handle) + start.append(name) + for arg in extra_arg: + start.append("-extra-arg=%s" % arg) + for arg in extra_arg_before: + start.append("-extra-arg-before=%s" % arg) + start.append("-p=" + build_path) + if quiet: + start.append("-quiet") + if config_file_path: + start.append("--config-file=" + config_file_path) + elif config: + start.append("-config=" + config) + for plugin in plugins: + start.append("-load=" + plugin) + start.append(f) + return start + + +def merge_replacement_files(tmpdir, mergefile): + """Merge all replacement files in a directory into a single file""" + # The fixes suggested by clang-tidy >= 4.0.0 are given under + # the top level key 'Diagnostics' in the output yaml files + mergekey = "Diagnostics" + merged = [] + for replacefile in glob.iglob(os.path.join(tmpdir, "*.yaml")): + content = yaml.safe_load(open(replacefile, "r")) + if not content: + continue # Skip empty files. + merged.extend(content.get(mergekey, [])) + + if merged: + # MainSourceFile: The key is required by the definition inside + # include/clang/Tooling/ReplacementsYaml.h, but the value + # is actually never used inside clang-apply-replacements, + # so we set it to '' here. + output = {"MainSourceFile": "", mergekey: merged} + with open(mergefile, "w") as out: + yaml.safe_dump(output, out) + else: + # Empty the file: + open(mergefile, "w").close() + + +def find_binary(arg, name, build_path): + """Get the path for a binary or exit""" + if arg: + if shutil.which(arg): + return arg + else: + raise SystemExit( + "error: passed binary '{}' was not found or is not executable".format( + arg + ) + ) + + built_path = os.path.join(build_path, "bin", name) + binary = shutil.which(name) or shutil.which(built_path) + if binary: + return binary + else: + raise SystemExit( + "error: failed to find {} in $PATH or at {}".format(name, built_path) + ) + + +def apply_fixes(args, clang_apply_replacements_binary, tmpdir): + """Calls clang-apply-fixes on a given directory.""" + invocation = [clang_apply_replacements_binary] + invocation.append("-ignore-insert-conflict") + if args.format: + invocation.append("-format") + if args.style: + invocation.append("-style=" + args.style) + invocation.append(tmpdir) + subprocess.call(invocation) + + +def run_tidy(args, clang_tidy_binary, tmpdir, build_path, queue, lock, failed_files): + """Takes filenames out of queue and runs clang-tidy on them.""" + while True: + name = queue.get() + invocation = get_tidy_invocation( + name, + clang_tidy_binary, + args.checks, + tmpdir, + build_path, + args.header_filter, + args.allow_enabling_alpha_checkers, + args.extra_arg, + args.extra_arg_before, + args.quiet, + args.config_file, + args.config, + args.line_filter, + args.use_color, + args.plugins, + ) + + proc = subprocess.Popen( + invocation, stdout=subprocess.PIPE, stderr=subprocess.PIPE + ) + output, err = proc.communicate() + if proc.returncode != 0: + if proc.returncode < 0: + msg = "%s: terminated by signal %d\n" % (name, -proc.returncode) + err += msg.encode("utf-8") + failed_files.append(name) + with lock: + sys.stdout.write(" ".join(invocation) + "\n" + output.decode("utf-8")) + if len(err) > 0: + sys.stdout.flush() + sys.stderr.write(err.decode("utf-8")) + queue.task_done() + + +def main(): + parser = argparse.ArgumentParser( + description="Runs clang-tidy over all files " + "in a compilation database. Requires " + "clang-tidy and clang-apply-replacements in " + "$PATH or in your build directory." + ) + parser.add_argument( + "-allow-enabling-alpha-checkers", + action="store_true", + help="allow alpha checkers from " "clang-analyzer.", + ) + parser.add_argument( + "-clang-tidy-binary", metavar="PATH", help="path to clang-tidy binary" + ) + parser.add_argument( + "-clang-apply-replacements-binary", + metavar="PATH", + help="path to clang-apply-replacements binary", + ) + parser.add_argument( + "-checks", + default=None, + help="checks filter, when not specified, use clang-tidy " "default", + ) + config_group = parser.add_mutually_exclusive_group() + config_group.add_argument( + "-config", + default=None, + help="Specifies a configuration in YAML/JSON format: " + " -config=\"{Checks: '*', " + ' CheckOptions: {x: y}}" ' + "When the value is empty, clang-tidy will " + "attempt to find a file named .clang-tidy for " + "each source file in its parent directories.", + ) + config_group.add_argument( + "-config-file", + default=None, + help="Specify the path of .clang-tidy or custom config " + "file: e.g. -config-file=/some/path/myTidyConfigFile. " + "This option internally works exactly the same way as " + "-config option after reading specified config file. " + "Use either -config-file or -config, not both.", + ) + parser.add_argument( + "-header-filter", + default=None, + help="regular expression matching the names of the " + "headers to output diagnostics from. Diagnostics from " + "the main file of each translation unit are always " + "displayed.", + ) + parser.add_argument( + "-line-filter", + default=None, + help="List of files with line ranges to filter the" "warnings.", + ) + if yaml: + parser.add_argument( + "-export-fixes", + metavar="filename", + dest="export_fixes", + help="Create a yaml file to store suggested fixes in, " + "which can be applied with clang-apply-replacements.", + ) + parser.add_argument( + "-j", + type=int, + default=0, + help="number of tidy instances to be run in parallel.", + ) + parser.add_argument( + "files", nargs="*", default=[".*"], help="files to be processed (regex on path)" + ) + parser.add_argument("-fix", action="store_true", help="apply fix-its") + parser.add_argument( + "-format", action="store_true", help="Reformat code " "after applying fixes" + ) + parser.add_argument( + "-style", + default="file", + help="The style of reformat " "code after applying fixes", + ) + parser.add_argument( + "-use-color", + type=strtobool, + nargs="?", + const=True, + help="Use colors in diagnostics, overriding clang-tidy's" + " default behavior. This option overrides the 'UseColor" + "' option in .clang-tidy file, if any.", + ) + parser.add_argument( + "-p", dest="build_path", help="Path used to read a compile command database." + ) + parser.add_argument( + "-extra-arg", + dest="extra_arg", + action="append", + default=[], + help="Additional argument to append to the compiler " "command line.", + ) + parser.add_argument( + "-extra-arg-before", + dest="extra_arg_before", + action="append", + default=[], + help="Additional argument to prepend to the compiler " "command line.", + ) + parser.add_argument( + "-quiet", action="store_true", help="Run clang-tidy in quiet mode" + ) + parser.add_argument( + "-load", + dest="plugins", + action="append", + default=[], + help="Load the specified plugin in clang-tidy.", + ) + args = parser.parse_args() + + db_path = "compile_commands.json" + + if args.build_path is not None: + build_path = args.build_path + else: + # Find our database + build_path = find_compilation_database(db_path) + + clang_tidy_binary = find_binary(args.clang_tidy_binary, "clang-tidy", build_path) + + tmpdir = None + if args.fix or (yaml and args.export_fixes): + clang_apply_replacements_binary = find_binary( + args.clang_apply_replacements_binary, "clang-apply-replacements", build_path + ) + tmpdir = tempfile.mkdtemp() + + try: + invocation = get_tidy_invocation( + "", + clang_tidy_binary, + args.checks, + None, + build_path, + args.header_filter, + args.allow_enabling_alpha_checkers, + args.extra_arg, + args.extra_arg_before, + args.quiet, + args.config_file, + args.config, + args.line_filter, + args.use_color, + args.plugins, + ) + invocation.append("-list-checks") + invocation.append("-") + if args.quiet: + # Even with -quiet we still want to check if we can call clang-tidy. + with open(os.devnull, "w") as dev_null: + subprocess.check_call(invocation, stdout=dev_null) + else: + subprocess.check_call(invocation) + except: + print("Unable to run clang-tidy.", file=sys.stderr) + sys.exit(1) + + # Load the database and extract all files. + database = json.load(open(os.path.join(build_path, db_path))) + files = set( + [make_absolute(entry["file"], entry["directory"]) for entry in database] + ) + + max_task = args.j + if max_task == 0: + max_task = multiprocessing.cpu_count() + + # Build up a big regexy filter from all command line arguments. + file_name_re = re.compile("|".join(args.files)) + + return_code = 0 + try: + # Spin up a bunch of tidy-launching threads. + task_queue = queue.Queue(max_task) + # List of files with a non-zero return code. + failed_files = [] + lock = threading.Lock() + for _ in range(max_task): + t = threading.Thread( + target=run_tidy, + args=( + args, + clang_tidy_binary, + tmpdir, + build_path, + task_queue, + lock, + failed_files, + ), + ) + t.daemon = True + t.start() + + # Fill the queue with files. + for name in files: + if file_name_re.search(name): + task_queue.put(name) + + # Wait for all threads to be done. + task_queue.join() + if len(failed_files): + return_code = 1 + + except KeyboardInterrupt: + # This is a sad hack. Unfortunately subprocess goes + # bonkers with ctrl-c and we start forking merrily. + print("\nCtrl-C detected, goodbye.") + if tmpdir: + shutil.rmtree(tmpdir) + os.kill(0, 9) + + if yaml and args.export_fixes: + print("Writing fixes to " + args.export_fixes + " ...") + try: + merge_replacement_files(tmpdir, args.export_fixes) + except: + print("Error exporting fixes.\n", file=sys.stderr) + traceback.print_exc() + return_code = 1 + + if args.fix: + print("Applying fixes ...") + try: + apply_fixes(args, clang_apply_replacements_binary, tmpdir) + except: + print("Error applying fixes.\n", file=sys.stderr) + traceback.print_exc() + return_code = 1 + + if tmpdir: + shutil.rmtree(tmpdir) + sys.exit(return_code) + + +if __name__ == "__main__": + main() From e86f5d8253b8de2959618710456e7728cf07e928 Mon Sep 17 00:00:00 2001 From: Brli <brli@chakralinux.org> Date: Sun, 17 Mar 2024 15:32:49 +0800 Subject: [PATCH 3/7] set KDE_COMPILERSETTINGS_LEVEL to 5.85.0 --- CMakeLists.txt | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index fc8afab..c5b4474 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,17 +1,19 @@ -cmake_minimum_required(VERSION 2.8.12) +cmake_minimum_required(VERSION 3.20.6) project(kmozillahelper) -set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11") +set(KF_MIN_VERSION "5.85.0") find_package( ECM - 1.0.0 + ${KF_MIN_VERSION} REQUIRED NO_MODULE) set(CMAKE_MODULE_PATH ${ECM_MODULE_PATH} ${ECM_KDE_MODULE_DIR}) +set(KDE_COMPILERSETTINGS_LEVEL ${KF_MIN_VERSION}) + include(KDEInstallDirs) include(KDECMakeSettings) include(KDECompilerSettings) @@ -24,7 +26,7 @@ find_package( WindowSystem I18n) -add_executable(kmozillahelper main.cpp) +add_executable(kmozillahelper main.cpp main.h) target_link_libraries( kmozillahelper From edd2308018dbd01bcd1acf8dd71e4abad9342af9 Mon Sep 17 00:00:00 2001 From: Brli <brli@chakralinux.org> Date: Sun, 17 Mar 2024 22:01:13 +0800 Subject: [PATCH 4/7] port main.cpp - NULL->nullptr - slaveProtocol -> workerProtocol - replace raw "string" with QString::fromUtf8() - rewrite handleGetProxy() fix main.h - protected virtual bool -> protected bool --- main.cpp | 191 ++++++++++++++++++++++++++++++------------------------- main.h | 5 +- 2 files changed, 106 insertions(+), 90 deletions(-) diff --git a/main.cpp b/main.cpp index 25b187e..76ec1b7 100644 --- a/main.cpp +++ b/main.cpp @@ -71,12 +71,12 @@ int main(int argc, char *argv[]) // Check whether we're called from Firefox or Thunderbird QString appname = i18n("Mozilla Firefox"); - QString parent = QFile::symLinkTarget(QStringLiteral("/proc/%1/exe").arg(int(getppid()))); - if (parent.contains("thunderbird", Qt::CaseInsensitive)) + QString parent = QFile::symLinkTarget(QString::fromUtf8("/proc/%1/exe").arg(int(getppid()))); + if (parent.contains(QString::fromUtf8("thunderbird"), Qt::CaseInsensitive)) appname = i18n("Mozilla Thunderbird"); // This shows on file dialogs - KAboutData about("kmozillahelper", appname, APP_HELPER_VERSION); + KAboutData about(QString::fromUtf8("kmozillahelper"), appname, QString::fromUtf8(APP_HELPER_VERSION)); about.setBugAddress("https://bugzilla.opensuse.org/enter_bug.cgi"); KAboutData::setApplicationData(about); QApplication::setQuitOnLastWindowClosed(false); @@ -122,49 +122,49 @@ void Helper::readCommand() std::cerr << "COMMAND: " << command.toStdString() << std::endl; #endif bool status; - if (command == "CHECK") + if (command == QString::fromUtf8("CHECK")) status = handleCheck(); - else if (command == "GETPROXY") + else if (command == QString::fromUtf8("GETPROXY")) status = handleGetProxy(); - else if (command == "HANDLEREXISTS") + else if (command == QString::fromUtf8("HANDLEREXISTS")) status = handleHandlerExists(); - else if (command == "GETFROMEXTENSION") + else if (command == QString::fromUtf8("GETFROMEXTENSION")) status = handleGetFromExtension(); - else if (command == "GETFROMTYPE") + else if (command == QString::fromUtf8("GETFROMTYPE")) status = handleGetFromType(); - else if (command == "GETAPPDESCFORSCHEME") + else if (command == QString::fromUtf8("GETAPPDESCFORSCHEME")) status = handleGetAppDescForScheme(); - else if (command == "APPSDIALOG") + else if (command == QString::fromUtf8("APPSDIALOG")) status = handleAppsDialog(); - else if (command == "GETOPENFILENAME") + else if (command == QString::fromUtf8("GETOPENFILENAME")) status = handleGetOpenOrSaveX(false, false); - else if (command == "GETOPENURL") + else if (command == QString::fromUtf8("GETOPENURL")) status = handleGetOpenOrSaveX(true, false); - else if (command == "GETSAVEFILENAME") + else if (command == QString::fromUtf8("GETSAVEFILENAME")) status = handleGetOpenOrSaveX(false, true); - else if (command == "GETSAVEURL") + else if (command == QString::fromUtf8("GETSAVEURL")) status = handleGetOpenOrSaveX(true, true); - else if (command == "GETDIRECTORYFILENAME") + else if (command == QString::fromUtf8("GETDIRECTORYFILENAME")) status = handleGetDirectoryX(false); - else if (command == "GETDIRECTORYURL") + else if (command == QString::fromUtf8("GETDIRECTORYURL")) status = handleGetDirectoryX(true); - else if (command == "OPEN") + else if (command == QString::fromUtf8("OPEN")) status = handleOpen(); - else if (command == "REVEAL") + else if (command == QString::fromUtf8("REVEAL")) status = handleReveal(); - else if (command == "RUN") + else if (command == QString::fromUtf8("RUN")) status = handleRun(); - else if (command == "GETDEFAULTFEEDREADER") + else if (command == QString::fromUtf8("GETDEFAULTFEEDREADER")) status = handleGetDefaultFeedReader(); - else if (command == "OPENMAIL") + else if (command == QString::fromUtf8("OPENMAIL")) status = handleOpenMail(); - else if (command == "OPENNEWS") + else if (command == QString::fromUtf8("OPENNEWS")) status = handleOpenNews(); - else if (command == "ISDEFAULTBROWSER") + else if (command == QString::fromUtf8("ISDEFAULTBROWSER")) status = handleIsDefaultBrowser(); - else if (command == "SETDEFAULTBROWSER") + else if (command == QString::fromUtf8("SETDEFAULTBROWSER")) status = handleSetDefaultBrowser(); - else if (command == "DOWNLOADFINISHED") + else if (command == QString::fromUtf8("DOWNLOADFINISHED")) status = handleDownloadFinished(); else { @@ -173,7 +173,7 @@ void Helper::readCommand() } // status done as \1 (==ok) and \0 (==not ok), because otherwise this cannot happen // in normal data (\ is escaped otherwise) - outputLine(status ? "\\1" : "\\0", false); // do not escape + outputLine(status ? QString::fromUtf8("\\1") : QString::fromUtf8("\\0"), false); // do not escape /* See comment on setEnabled above notifier.setEnabled(true); */ @@ -194,25 +194,33 @@ bool Helper::handleCheck() bool Helper::handleGetProxy() { + // expect to be fed with argument: [protocol://]domain.tld:port if (!readArguments(1)) return false; QUrl url = QUrl::fromUserInput(getArgument()); if (!allArgumentsUsed()) return false; - QString proxy; - KProtocolManager::slaveProtocol(url, proxy); - if (proxy.isEmpty() || proxy == "DIRECT") // TODO return DIRECT if empty? + + // get the url elements + // if only the doamin.tld is given, aka. without protocol, this method returns http by default + QString proxy = url.scheme(); + + // if the url is valid, we check if it's a proxy + // return DIRECT otherwise + if (url.isValid()) { - outputLine("DIRECT"); - return true; - } - QUrl proxyurl = QUrl::fromUserInput(proxy); - if (proxyurl.isValid()) - { // firefox wants this format - outputLine("PROXY" - " " + - proxyurl.host() + ":" + QString::number(proxyurl.port())); - // TODO there is also "SOCKS " type + if(proxy == QString::fromUtf8("PROXY") || proxy == QString::fromUtf8("SOCKS5")) + { + // ref. https://developer.mozilla.org/en-US/docs/Web/HTTP/Proxy_servers_and_tunneling/Proxy_Auto-Configuration_PAC_file + // format: "PROXY hostname:port" + outputLine(proxy.toUpper() + QString::fromUtf8(" ") + url.host() + QString::fromUtf8(":") + + QString::number(url.port())); + } + else + { + // we don't deal with other protocols + outputLine(QString::fromUtf8("DIRECT")); + } return true; } return false; @@ -248,7 +256,7 @@ bool Helper::handleGetFromExtension() return false; if (!ext.isEmpty()) { - QList<QMimeType> mimeList = QMimeDatabase().mimeTypesForFileName("foo." + ext); + QList<QMimeType> mimeList = QMimeDatabase().mimeTypesForFileName(QString::fromUtf8("foo.") + ext); for (const QMimeType &mime : mimeList) if (mime.isValid()) return writeMimeInfo(mime); @@ -315,7 +323,7 @@ bool Helper::handleAppsDialog() long wid = getArgumentParent(); if (!allArgumentsUsed()) return false; - KOpenWithDialog dialog(NULL); + KOpenWithDialog dialog(nullptr); if (!title.isEmpty()) dialog.setWindowTitle(title); dialog.hideNoCloseOnExit(); @@ -337,7 +345,7 @@ bool Helper::handleAppsDialog() command = dialog.text(); else return false; - command = command.split(" ").first(); // only the actual command + command = command.split(QString::fromUtf8(" ")).first(); // only the actual command command = QStandardPaths::findExecutable(command); if (command.isEmpty()) return false; @@ -352,11 +360,11 @@ QStringList Helper::convertToNameFilters(const QString &input) QStringList ret; // Filters separated by newline - for (auto &filter : input.split('\n')) + for (auto &filter : input.split(QLatin1Char('\n'))) { // Filer exp and name separated by '|'. // TODO: Is it possible that | appears in either of those? - auto data = filter.split('|'); + auto data = filter.split(QLatin1Char('|')); if (data.length() == 1) ret.append(QStringLiteral("%0 Files(%0)").arg(data[0])); @@ -376,7 +384,7 @@ bool Helper::handleGetOpenOrSaveX(bool url, bool save) QStringList filtersParsed = convertToNameFilters(getArgument()); int selectFilter = getArgument().toInt(); QString title = getArgument(); - bool multiple = save ? false : isArgument("MULTIPLE"); + bool multiple = save ? false : isArgument(QString::fromUtf8("MULTIPLE")); this->wid = getArgumentParent(); if (!allArgumentsUsed()) return false; @@ -450,7 +458,7 @@ bool Helper::handleGetDirectoryX(bool url) if (url) { - QUrl result = QFileDialog::getExistingDirectoryUrl(nullptr, title, startDir); + QUrl result = QFileDialog::getExistingDirectoryUrl(nullptr, title, QUrl::fromLocalFile(startDir)); if (result.isValid()) { outputLine(result.url()); @@ -475,7 +483,7 @@ bool Helper::handleOpen() return false; QUrl url = QUrl::fromUserInput(getArgument()); QString mime; - if (isArgument("MIMETYPE")) + if (isArgument(QString::fromUtf8("MIMETYPE"))) mime = getArgument(); if (!allArgumentsUsed()) return false; @@ -492,21 +500,24 @@ bool Helper::handleReveal() QString path = getArgument(); if (!allArgumentsUsed()) return false; - const KService::List apps = KMimeTypeTrader::self()->query("inode/directory", "Application"); + const KService::List apps = + KMimeTypeTrader::self()->query(QString::fromUtf8("inode/directory"), QString::fromUtf8("Application")); if (apps.size() != 0) { - QString command = apps.at(0)->exec().split(" ").first(); // only the actual command - if (command == "dolphin" || command == "konqueror") + QString command = apps.at(0)->exec().split(QString::fromLatin1(" ")).first(); // only the actual command + if (command == QString::fromUtf8("dolphin") || command == QString::fromUtf8("konqueror")) { command = QStandardPaths::findExecutable(command); if (command.isEmpty()) + { return false; - return KProcess::startDetached(command, QStringList() << "--select" << path); + } + return KProcess::startDetached(command, QStringList() << QString::fromUtf8("--select") << path); } } QFileInfo info(path); QString dir = info.dir().path(); - (void)new KRun(QUrl::fromLocalFile(dir), NULL); // TODO parent + (void)new KRun(QUrl::fromLocalFile(dir), nullptr); // TODO parent return true; // TODO check for errors? } @@ -518,7 +529,8 @@ bool Helper::handleRun() QString arg = getArgument(); if (!allArgumentsUsed()) return false; - return KRun::runCommand(KShell::quoteArg(app) + " " + KShell::quoteArg(arg), NULL); // TODO parent, ASN + return KRun::runCommand(KShell::quoteArg(app) + QString::fromUtf8(" ") + KShell::quoteArg(arg), + nullptr); // TODO parent, ASN } bool Helper::handleGetDefaultFeedReader() @@ -526,7 +538,8 @@ bool Helper::handleGetDefaultFeedReader() if (!readArguments(0)) return false; // firefox wants the full path - QString reader = QStandardPaths::findExecutable("akregator"); // TODO there is no KDE setting for this + QString reader = + QStandardPaths::findExecutable(QString::fromUtf8("akregator")); // TODO there is no KDE setting for this if (!reader.isEmpty()) { outputLine(reader); @@ -540,22 +553,22 @@ bool Helper::handleOpenMail() if (!readArguments(0)) return false; // this is based on ktoolinvocation_x11.cpp, there is no API for this - KConfig config("emaildefaults"); + KConfig config(QString::fromUtf8("emaildefaults")); QString groupname = KConfigGroup(&config, "Defaults").readEntry("Profile", "Default"); - KConfigGroup group(&config, QString("PROFILE_%1").arg(groupname)); + KConfigGroup group(&config, QString::fromStdString("PROFILE_%1").arg(groupname)); QString command = group.readPathEntry("EmailClient", QString()); if (command.isEmpty()) - command = "kmail"; + command = QString::fromUtf8("kmail"); if (group.readEntry("TerminalClient", false)) { - QString terminal = - KConfigGroup(KSharedConfig::openConfig(), "General").readPathEntry("TerminalApplication", "konsole"); - command = terminal + " -e " + command; + QString terminal = KConfigGroup(KSharedConfig::openConfig(), "General") + .readPathEntry("TerminalApplication", QString::fromUtf8("konsole")); + command = terminal + QString::fromUtf8(" -e ") + command; } - KService::Ptr mail = KService::serviceByDesktopName(command.split(" ").first()); + KService::Ptr mail = KService::serviceByDesktopName(command.split(QLatin1Char(' ')).first()); if (mail) { - return KRun::runService(*mail, QList<QUrl>(), NULL); // TODO parent + return KRun::runService(*mail, QList<QUrl>(), nullptr); // TODO parent } return false; } @@ -564,11 +577,12 @@ bool Helper::handleOpenNews() { if (!readArguments(0)) return false; - KService::Ptr news = KService::serviceByDesktopName("knode"); // TODO there is no KDE setting for this + KService::Ptr news = + KService::serviceByDesktopName(QString::fromUtf8("knode")); // TODO there is no KDE setting for this if (news) { //KApplication::updateUserTimestamp(0); // TODO - return KRun::runService(*news, QList<QUrl>(), NULL); // TODO parent + return KRun::runService(*news, QList<QUrl>(), nullptr); // TODO parent } return false; } @@ -577,19 +591,22 @@ bool Helper::handleIsDefaultBrowser() { if (!readArguments(0)) return false; - QString browser = KConfigGroup(KSharedConfig::openConfig("kdeglobals"), "General").readEntry("BrowserApplication"); - return browser == "MozillaFirefox" || browser == "MozillaFirefox.desktop" || browser == "!firefox" || - browser == "!/usr/bin/firefox" || browser == "firefox" || browser == "firefox.desktop"; + QString browser = KConfigGroup(KSharedConfig::openConfig(QString::fromUtf8("kdeglobals")), "General") + .readEntry("BrowserApplication"); + return browser == QString::fromUtf8("MozillaFirefox") || browser == QString::fromUtf8("MozillaFirefox.desktop") || + browser == QString::fromUtf8("!firefox") || browser == QString::fromUtf8("!/usr/bin/firefox") || + browser == QString::fromUtf8("firefox") || browser == QString::fromUtf8("firefox.desktop"); } bool Helper::handleSetDefaultBrowser() { if (!readArguments(1)) return false; - bool alltypes = (getArgument() == "ALLTYPES"); + bool alltypes = (getArgument() == QString::fromUtf8("ALLTYPES")); if (!allArgumentsUsed()) return false; - KConfigGroup(KSharedConfig::openConfig("kdeglobals"), "General").writeEntry("BrowserApplication", "firefox"); + KConfigGroup(KSharedConfig::openConfig(QString::fromUtf8("kdeglobals")), "General") + .writeEntry("BrowserApplication", "firefox"); if (alltypes) { // TODO there is no API for this and it is a bit complex @@ -607,9 +624,9 @@ bool Helper::handleDownloadFinished() // TODO cheat a bit due to i18n freeze - the strings are in the .notifyrc file, // taken from KGet, but the notification itself needs the text too. // So create it from there. - KConfig cfg("kmozillahelper.notifyrc", KConfig::FullConfig, QStandardPaths::AppDataLocation); + KConfig cfg(QString::fromUtf8("kmozillahelper.notifyrc"), KConfig::FullConfig, QStandardPaths::AppDataLocation); QString message = KConfigGroup(&cfg, "Event/downloadfinished").readEntry("Comment"); - KNotification::event("downloadfinished", download + " : " + message); + KNotification::event(QString::fromUtf8("downloadfinished"), download + QString::fromUtf8(" : ") + message); return true; } @@ -636,18 +653,18 @@ QString Helper::getAppForProtocol(const QString &protocol) if (exec.isEmpty()) return {}; - if (exec.contains(' ')) - exec = exec.split(' ').first(); // first part of command + if (exec.contains(QLatin1Char(' '))) + exec = exec.split(QLatin1Char(' ')).first(); // first part of command if (KService::Ptr service = KService::serviceByDesktopName(exec)) return service->name(); QString servicename; - foreach (KService::Ptr service, KService::allServices()) + for (KService::Ptr service : KService::allServices()) { QString exec2 = service->exec(); - if (exec2.contains(' ')) - exec2 = exec2.split(' ').first(); // first part of command + if (exec2.contains(QLatin1Char(' '))) + exec2 = exec2.split(QLatin1Char(' ')).first(); // first part of command if (exec == exec2) { servicename = service->name(); @@ -655,7 +672,8 @@ QString Helper::getAppForProtocol(const QString &protocol) } } - if (servicename.isEmpty() && exec == "kmailservice") // kmailto is handled internally by kmailservice + if (servicename.isEmpty() && + exec == QString::fromUtf8("kmailservice")) // kmailto is handled internally by kmailservice servicename = i18n("KDE"); return servicename; @@ -668,10 +686,8 @@ QString Helper::readLine() return {}; QString qline = QString::fromStdString(line); - qline.replace("\\n", "\n"); - qline.replace("\\" - "\\", - "\\"); + qline.replace(QString::fromUtf8("\\n"), QString::fromUtf8("\n")); + qline.replace(QString::fromUtf8("\\\\"), QString::fromUtf8("\\")); return qline; } @@ -700,10 +716,8 @@ void Helper::outputLine(QString line, bool escape) { if (escape) { - line.replace("\\", - "\\" - "\\"); - line.replace("\n", "\\n"); + line.replace(QString::fromUtf8("\\\\"), QString::fromUtf8("\\")); + line.replace(QString::fromUtf8("\n"), QString::fromUtf8("\\n")); } std::cout << line.toStdString() << std::endl; #ifdef DEBUG_KDE @@ -722,7 +736,7 @@ bool Helper::readArguments(int mincount) arguments.clear(); return false; } - if (line == "\\E") + if (line == QString::fromUtf8("\\E")) { arguments_read = true; if (arguments.count() >= mincount) @@ -756,14 +770,15 @@ bool Helper::allArgumentsUsed() arguments_read = false; if (arguments.isEmpty()) return true; - std::cerr << "Unused arguments for KDE helper:" << arguments.join(" ").toStdString() << std::endl; + std::cerr << "Unused arguments for KDE helper:" << arguments.join(QString::fromUtf8(" ")).toStdString() + << std::endl; arguments.clear(); return false; } long Helper::getArgumentParent() { - if (isArgument("PARENT")) + if (isArgument(QString::fromUtf8("PARENT"))) return getArgument().toLong(); return 0; } diff --git a/main.h b/main.h index f728337..63c17b3 100644 --- a/main.h +++ b/main.h @@ -64,8 +64,9 @@ class Helper : public QObject QString readLine(); protected: - virtual bool eventFilter(QObject *obj, QEvent *ev) override; -private slots: + bool eventFilter(QObject *obj, QEvent *event) override; + + Q_SLOT void readCommand(); private: From 888c8d5ce2e947c9e3be50ebcbc9b7fa47a5b57a Mon Sep 17 00:00:00 2001 From: Brli <brli@chakralinux.org> Date: Tue, 19 Mar 2024 20:23:32 +0800 Subject: [PATCH 5/7] main.cpp: port away from deprecated usages - replace KRun:runService with KIO/ApplicationLauncherJob - replace KRun() with KIO/OpenUrlJob - replace Krun::runCommand with KIO/CommandLauncherJob - replace KMimeTypeTrader with KApplicationTrader --- main.cpp | 59 ++++++++++++++++++++++++++++++++++++++++---------------- 1 file changed, 42 insertions(+), 17 deletions(-) diff --git a/main.cpp b/main.cpp index 76ec1b7..5b650a8 100644 --- a/main.cpp +++ b/main.cpp @@ -44,12 +44,20 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. #include <KCoreAddons/KProcess> #include <KCoreAddons/KShell> #include <KI18n/KLocalizedString> +#include <KIO/ApplicationLauncherJob> +#include <KIO/CommandLauncherJob> +#include <KService/KApplicationTrader> +#include <kio_version.h> +#if KIO_VERSION >= QT_VERSION_CHECK(5, 98, 0) +#include <KIO/JobUiDelegateFactory> +#else +#include <KIO/JobUiDelegate> +#endif #include <KIO/OpenUrlJob> -#include <KIOCore/KProtocolManager> #include <KIOCore/KRecentDocument> #include <KIOWidgets/KOpenWithDialog> -#include <KIOWidgets/KRun> #include <KNotifications/KNotification> +#include <KProtocolInfo> #include <KService/KMimeTypeTrader> #include <KWindowSystem/KWindowSystem> @@ -98,6 +106,19 @@ Helper::Helper() : notifier(STDIN_FILENO, QSocketNotifier::Read), arguments_read connect(¬ifier, &QSocketNotifier::activated, this, &Helper::readCommand); } +static bool runApplication(const KService::Ptr &service, const QList<QUrl> &urls) +{ + auto *job = new KIO::ApplicationLauncherJob(service); + job->setUrls(urls); +#if KIO_VERSION >= QT_VERSION_CHECK(5, 98, 0) + job->setUiDelegate(KIO::createDefaultJobUiDelegate(KJobUiDelegate::AutoHandlingEnabled, nullptr)); +#else + job->setUiDelegate(new KIO::JobUiDelegate(KJobUiDelegate::AutoHandlingEnabled, nullptr)); +#endif + job->start(); + return true; +} + void Helper::readCommand() { QString command = readLine(); @@ -209,12 +230,12 @@ bool Helper::handleGetProxy() // return DIRECT otherwise if (url.isValid()) { - if(proxy == QString::fromUtf8("PROXY") || proxy == QString::fromUtf8("SOCKS5")) + if (proxy == QString::fromUtf8("PROXY") || proxy == QString::fromUtf8("SOCKS5")) { // ref. https://developer.mozilla.org/en-US/docs/Web/HTTP/Proxy_servers_and_tunneling/Proxy_Auto-Configuration_PAC_file // format: "PROXY hostname:port" outputLine(proxy.toUpper() + QString::fromUtf8(" ") + url.host() + QString::fromUtf8(":") + - QString::number(url.port())); + QString::number(url.port())); } else { @@ -244,7 +265,7 @@ bool Helper::handleHandlerExists() if (*it) return true; - return KMimeTypeTrader::self()->preferredService(QLatin1String("x-scheme-handler/") + protocol) != nullptr; + return KApplicationTrader::preferredService(QLatin1String("x-scheme-handler/") + protocol) != nullptr; } bool Helper::handleGetFromExtension() @@ -288,7 +309,7 @@ bool Helper::handleGetFromType() bool Helper::writeMimeInfo(QMimeType mime) { - KService::Ptr service = KMimeTypeTrader::self()->preferredService(mime.name()); + KService::Ptr service = KApplicationTrader::preferredService(mime.name()); if (service) { outputLine(mime.name()); @@ -369,7 +390,7 @@ QStringList Helper::convertToNameFilters(const QString &input) if (data.length() == 1) ret.append(QStringLiteral("%0 Files(%0)").arg(data[0])); else if (data.length() >= 2) - ret.append(QStringLiteral("%0 (%1)(%1)").arg(data[1]).arg(data[0])); + ret.append(QStringLiteral("%0 (%1)(%1)").arg(data[1], data[0])); } return ret; @@ -500,8 +521,7 @@ bool Helper::handleReveal() QString path = getArgument(); if (!allArgumentsUsed()) return false; - const KService::List apps = - KMimeTypeTrader::self()->query(QString::fromUtf8("inode/directory"), QString::fromUtf8("Application")); + const KService::List apps = KApplicationTrader::queryByMimeType(QString::fromUtf8("inode/directory")); if (apps.size() != 0) { QString command = apps.at(0)->exec().split(QString::fromLatin1(" ")).first(); // only the actual command @@ -517,8 +537,8 @@ bool Helper::handleReveal() } QFileInfo info(path); QString dir = info.dir().path(); - (void)new KRun(QUrl::fromLocalFile(dir), nullptr); // TODO parent - return true; // TODO check for errors? + (void)new KIO::OpenUrlJob(QUrl::fromLocalFile(dir), nullptr); + return true; // TODO check for errors? } bool Helper::handleRun() @@ -529,8 +549,14 @@ bool Helper::handleRun() QString arg = getArgument(); if (!allArgumentsUsed()) return false; - return KRun::runCommand(KShell::quoteArg(app) + QString::fromUtf8(" ") + KShell::quoteArg(arg), - nullptr); // TODO parent, ASN + auto job = new KIO::CommandLauncherJob(KShell::quoteArg(app), {KShell::quoteArg(arg)}); +#if KIO_VERSION >= QT_VERSION_CHECK(5, 98, 0) + job->setUiDelegate(KIO::createDefaultJobUiDelegate(KJobUiDelegate::AutoHandlingEnabled, nullptr)); +#else + job->setUiDelegate(new KIO::JobUiDelegate(KJobUiDelegate::AutoHandlingEnabled, nullptr)); +#endif + job->start(); + return true; } bool Helper::handleGetDefaultFeedReader() @@ -568,7 +594,7 @@ bool Helper::handleOpenMail() KService::Ptr mail = KService::serviceByDesktopName(command.split(QLatin1Char(' ')).first()); if (mail) { - return KRun::runService(*mail, QList<QUrl>(), nullptr); // TODO parent + return runApplication(mail, QList<QUrl>()); // TODO parent } return false; } @@ -582,7 +608,7 @@ bool Helper::handleOpenNews() if (news) { //KApplication::updateUserTimestamp(0); // TODO - return KRun::runService(*news, QList<QUrl>(), nullptr); // TODO parent + return runApplication(news, QList<QUrl>()); // TODO parent } return false; } @@ -633,8 +659,7 @@ bool Helper::handleDownloadFinished() QString Helper::getAppForProtocol(const QString &protocol) { /* Inspired by kio's krun.cpp */ - const KService::Ptr service = - KMimeTypeTrader::self()->preferredService(QLatin1String("x-scheme-handler/") + protocol); + const KService::Ptr service = KApplicationTrader::preferredService(QLatin1String("x-scheme-handler/") + protocol); if (service) return service->name(); From 1660df3d7e0dc78861de6f8eb83f57c8e37db958 Mon Sep 17 00:00:00 2001 From: Brli <brli@chakralinux.org> Date: Tue, 19 Mar 2024 21:55:08 +0800 Subject: [PATCH 6/7] main.cpp: make openUrl a static function --- main.cpp | 31 ++++++++++++++++++++----------- 1 file changed, 20 insertions(+), 11 deletions(-) diff --git a/main.cpp b/main.cpp index 5b650a8..d3b9fbf 100644 --- a/main.cpp +++ b/main.cpp @@ -119,6 +119,18 @@ static bool runApplication(const KService::Ptr &service, const QList<QUrl> &urls return true; } +static bool openUrl(QUrl url, QString *mime) +{ + auto *job = new KIO::OpenUrlJob(url, *mime); +#if KIO_VERSION >= QT_VERSION_CHECK(5, 98, 0) + job->setUiDelegate(KIO::createDefaultJobUiDelegate(KJobUiDelegate::AutoHandlingEnabled, nullptr)); +#else + job->setUiDelegate(new KIO::JobUiDelegate(KJobUiDelegate::AutoHandlingEnabled, nullptr)); +#endif + job->start(); + return true; +} + void Helper::readCommand() { QString command = readLine(); @@ -222,18 +234,18 @@ bool Helper::handleGetProxy() if (!allArgumentsUsed()) return false; - // get the url elements - // if only the doamin.tld is given, aka. without protocol, this method returns http by default + /* get the url elements + if only the doamin.tld is given, aka. without protocol, this method returns http by default */ QString proxy = url.scheme(); - // if the url is valid, we check if it's a proxy - // return DIRECT otherwise + /* if the url is valid, we check if it's a proxy + return DIRECT otherwise */ if (url.isValid()) { if (proxy == QString::fromUtf8("PROXY") || proxy == QString::fromUtf8("SOCKS5")) { - // ref. https://developer.mozilla.org/en-US/docs/Web/HTTP/Proxy_servers_and_tunneling/Proxy_Auto-Configuration_PAC_file - // format: "PROXY hostname:port" + /* ref. https://developer.mozilla.org/en-US/docs/Web/HTTP/Proxy_servers_and_tunneling/Proxy_Auto-Configuration_PAC_file + / format: "PROXY hostname:port" */ outputLine(proxy.toUpper() + QString::fromUtf8(" ") + url.host() + QString::fromUtf8(":") + QString::number(url.port())); } @@ -509,9 +521,7 @@ bool Helper::handleOpen() if (!allArgumentsUsed()) return false; - auto ouj = new KIO::OpenUrlJob(url, mime); - ouj->start(); - return true; + return openUrl(url, &mime); } bool Helper::handleReveal() @@ -537,8 +547,7 @@ bool Helper::handleReveal() } QFileInfo info(path); QString dir = info.dir().path(); - (void)new KIO::OpenUrlJob(QUrl::fromLocalFile(dir), nullptr); - return true; // TODO check for errors? + return openUrl(QUrl::fromLocalFile(dir), nullptr); } bool Helper::handleRun() From 0c38e722fd1a17303467f29e07a77a0a5a9a300b Mon Sep 17 00:00:00 2001 From: Brli <brli@chakralinux.org> Date: Wed, 20 Mar 2024 17:06:47 +0800 Subject: [PATCH 7/7] remove .clang-format, use KDEClangFormat --- .clang-format | 207 +++++++++++++++++++------------------------------ CMakeLists.txt | 14 ++++ 2 files changed, 94 insertions(+), 127 deletions(-) diff --git a/.clang-format b/.clang-format index 3241cee..cf5ff2c 100644 --- a/.clang-format +++ b/.clang-format @@ -1,135 +1,88 @@ --- -Language: Cpp -AccessModifierOffset: -4 +# SPDX-FileCopyrightText: 2019 Christoph Cullmann <cullmann@kde.org> +# SPDX-FileCopyrightText: 2019 Gernot Gebhard <gebhard@absint.com> +# +# SPDX-License-Identifier: MIT + +# This file got automatically created by ECM, do not edit +# See https://clang.llvm.org/docs/ClangFormatStyleOptions.html for the config options +# and https://community.kde.org/Policies/Frameworks_Coding_Style#Clang-format_automatic_code_formatting +# for clang-format tips & tricks +--- +Language: JavaScript +DisableFormat: true +--- + +# Style for C++ +Language: Cpp + +# base is WebKit coding style: https://webkit.org/code-style-guidelines/ +# below are only things set that diverge from this style! +BasedOnStyle: WebKit + +# enforce C++11 (e.g. for std::vector<std::vector<lala>> +Standard: Cpp11 + +# 4 spaces indent +TabWidth: 4 + +# 2 * 80 wide lines +ColumnLimit: 160 + +# sort includes inside line separated groups +SortIncludes: true + +# break before braces on function, namespace and class definitions. +BreakBeforeBraces: Linux + +# CrlInstruction *a; +PointerAlignment: Right + +# horizontally aligns arguments after an open bracket. AlignAfterOpenBracket: Align -AlignConsecutiveMacros: false -AlignConsecutiveAssignments: false -AlignConsecutiveDeclarations: false -AlignEscapedNewlines: Right -AlignOperands: true -AlignTrailingComments: true -AllowAllArgumentsOnNextLine: false -AllowAllConstructorInitializersOnNextLine: true + +# don't move all parameters to new line AllowAllParametersOfDeclarationOnNextLine: false -AllowShortBlocksOnASingleLine: Never -AllowShortCaseLabelsOnASingleLine: false + +# no single line functions AllowShortFunctionsOnASingleLine: None -AllowShortLambdasOnASingleLine: All -AllowShortIfStatementsOnASingleLine: Never -AllowShortLoopsOnASingleLine: false -AlwaysBreakAfterDefinitionReturnType: None -AlwaysBreakAfterReturnType: None -AlwaysBreakBeforeMultilineStrings: false -AlwaysBreakTemplateDeclarations: Yes + +# always break before you encounter multi line strings +AlwaysBreakBeforeMultilineStrings: true + +# don't move arguments to own lines if they are not all on the same BinPackArguments: false + +# don't move parameters to own lines if they are not all on the same BinPackParameters: false -BraceWrapping: - AfterCaseLabel: true - AfterClass: true - AfterControlStatement: true - AfterEnum: true - AfterFunction: true - AfterNamespace: true - AfterObjCDeclaration: true - AfterStruct: true - AfterUnion: true - AfterExternBlock: true - BeforeCatch: true - BeforeElse: true - IndentBraces: false - SplitEmptyFunction: true - SplitEmptyRecord: true - SplitEmptyNamespace: true -BreakBeforeBinaryOperators: None -BreakBeforeBraces: Custom -BreakBeforeInheritanceComma: false -BreakInheritanceList: BeforeColon -BreakBeforeTernaryOperators: true -BreakConstructorInitializersBeforeComma: false -BreakConstructorInitializers: BeforeColon -BreakAfterJavaFieldAnnotations: false -BreakStringLiterals: true -ColumnLimit: 120 -CommentPragmas: '^ IWYU pragma:' -CompactNamespaces: false -ConstructorInitializerAllOnOneLineOrOnePerLine: false -ConstructorInitializerIndentWidth: 4 -ContinuationIndentWidth: 4 + +# In case we have an if statement with multiple lines the operator should be at the beginning of the line +# but we do not want to break assignments +BreakBeforeBinaryOperators: NonAssignment + +# format C++11 braced lists like function calls Cpp11BracedListStyle: true -DeriveLineEnding: true -DerivePointerAlignment: false -DisableFormat: false -ExperimentalAutoDetectBinPacking: false -FixNamespaceComments: true -ForEachMacros: - - foreach - - Q_FOREACH - - BOOST_FOREACH -IncludeBlocks: Preserve -IncludeCategories: - - Regex: '^"(llvm|llvm-c|clang|clang-c)/' - Priority: 2 - SortPriority: 0 - - Regex: '^(<|"(gtest|gmock|isl|json)/)' - Priority: 3 - SortPriority: 0 - - Regex: '.*' - Priority: 1 - SortPriority: 0 -IncludeIsMainRegex: '(Test)?$' -IncludeIsMainSourceRegex: '' -IndentCaseLabels: false -IndentGotoLabels: true -IndentPPDirectives: None -IndentWidth: 4 -IndentWrappedFunctionNames: false -JavaScriptQuotes: Leave -JavaScriptWrapImports: true -KeepEmptyLinesAtTheStartOfBlocks: true -MacroBlockBegin: '' -MacroBlockEnd: '' -MaxEmptyLinesToKeep: 2 -NamespaceIndentation: None -ObjCBinPackProtocolList: Auto -ObjCBlockIndentWidth: 2 -ObjCSpaceAfterProperty: false -ObjCSpaceBeforeProtocolList: true -PenaltyBreakAssignment: 2 -PenaltyBreakBeforeFirstCallParameter: 19 -PenaltyBreakComment: 300 -PenaltyBreakFirstLessLess: 120 -PenaltyBreakString: 1000 -PenaltyBreakTemplateDeclaration: 10 -PenaltyExcessCharacter: 1000000 -PenaltyReturnTypeOnItsOwnLine: 1000 -PointerAlignment: Right -ReflowComments: false -SortIncludes: true -SortUsingDeclarations: true -SpaceAfterCStyleCast: false -SpaceAfterLogicalNot: false -SpaceAfterTemplateKeyword: true -SpaceBeforeAssignmentOperators: true + +# do not put a space before C++11 braced lists SpaceBeforeCpp11BracedList: false -SpaceBeforeCtorInitializerColon: true -SpaceBeforeInheritanceColon: true -SpaceBeforeParens: ControlStatements -SpaceBeforeRangeBasedForLoopColon: true -SpaceInEmptyBlock: false -SpaceInEmptyParentheses: false -SpacesBeforeTrailingComments: 1 -SpacesInAngles: false -SpacesInConditionalStatement: false -SpacesInContainerLiterals: true -SpacesInCStyleCastParentheses: false -SpacesInParentheses: false -SpacesInSquareBrackets: false -SpaceBeforeSquareBrackets: false -Standard: Latest -StatementMacros: - - Q_UNUSED - - QT_REQUIRE_VERSION -TabWidth: 4 -UseCRLF: false -UseTab: Never -... + +# remove empty lines +KeepEmptyLinesAtTheStartOfBlocks: false + +# no namespace indentation to keep indent level low +NamespaceIndentation: None + +# we use template< without space. +SpaceAfterTemplateKeyword: false + +# Always break after template declaration +AlwaysBreakTemplateDeclarations: true + +# macros for which the opening brace stays attached. +ForEachMacros: [ foreach, Q_FOREACH, BOOST_FOREACH, forever, Q_FOREVER, QBENCHMARK, QBENCHMARK_ONCE , wl_resource_for_each, wl_resource_for_each_safe ] + +# keep lambda formatting multi-line if not empty +AllowShortLambdasOnASingleLine: Empty + +# We do not want clang-format to put all arguments on a new line +AllowAllArgumentsOnNextLine: false diff --git a/CMakeLists.txt b/CMakeLists.txt index c5b4474..01b20af 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -17,6 +17,8 @@ set(KDE_COMPILERSETTINGS_LEVEL ${KF_MIN_VERSION}) include(KDEInstallDirs) include(KDECMakeSettings) include(KDECompilerSettings) +include(KDEClangFormat) +include(KDEGitCommitHooks) include(FeatureSummary) find_package( @@ -35,5 +37,17 @@ target_link_libraries( KF5::Notifications KF5::WindowSystem) +# add clang-format target for all our real source files +file( + GLOB_RECURSE + ALL_CLANG_FORMAT_SOURCE_FILES + *.cpp + *.h) +kde_clang_format(${ALL_CLANG_FORMAT_SOURCE_FILES}) +kde_configure_git_pre_commit_hook(CHECKS CLANG_FORMAT) + +feature_summary(WHAT ALL INCLUDE_QUIET_PACKAGES + FATAL_ON_MISSING_REQUIRED_PACKAGES) + install(TARGETS kmozillahelper DESTINATION ${CMAKE_INSTALL_PREFIX}/lib/mozilla/) install(FILES kmozillahelper.notifyrc DESTINATION ${KNOTIFYRC_INSTALL_DIR})
Locations
Projects
Search
Status Monitor
Help
OpenBuildService.org
Documentation
API Documentation
Code of Conduct
Contact
Support
@OBShq
Terms
openSUSE Build Service is sponsored by
The Open Build Service is an
openSUSE project
.
Sign Up
Log In
Places
Places
All Projects
Status Monitor