implements Serializable {
13 |
14 | private String errmsg;
15 | private Long errcode;
16 | private T data;
17 |
18 | }
19 |
--------------------------------------------------------------------------------
/src/main/resources/icons/collapseAll.svg:
--------------------------------------------------------------------------------
1 |
2 |
6 |
--------------------------------------------------------------------------------
/src/main/resources/icons/expandAll.svg:
--------------------------------------------------------------------------------
1 |
2 |
6 |
--------------------------------------------------------------------------------
/src/main/resources/icons/collapseAll_dark.svg:
--------------------------------------------------------------------------------
1 |
2 |
6 |
--------------------------------------------------------------------------------
/src/main/resources/icons/expandAll_dark.svg:
--------------------------------------------------------------------------------
1 |
2 |
6 |
--------------------------------------------------------------------------------
/src/main/java/com/liuzhihang/doc/view/constant/JsonPropertyConstant.java:
--------------------------------------------------------------------------------
1 | package com.liuzhihang.doc.view.constant;
2 |
3 | /**
4 | * JsonProperty 配置
5 | *
6 | * @author liuzhihang
7 | * @since 2023/12/23 18:42
8 | */
9 | public class JsonPropertyConstant {
10 | private JsonPropertyConstant() {
11 | }
12 |
13 | /**
14 | * 注解 @JsonProperty 的全路径
15 | */
16 | public static final String JSON_PROPERTY = "com.fasterxml.jackson.annotation.JsonProperty";
17 |
18 | }
19 |
--------------------------------------------------------------------------------
/src/main/java/com/liuzhihang/doc/view/integration/dto/YApiQuery.java:
--------------------------------------------------------------------------------
1 | package com.liuzhihang.doc.view.integration.dto;
2 |
3 | import lombok.Data;
4 |
5 | /**
6 | * @author liuzhihang
7 | * @date 2021/6/8 22:58
8 | */
9 | @Data
10 | public class YApiQuery {
11 |
12 | private String name;
13 |
14 | private String type;
15 |
16 | private String example;
17 |
18 | private String desc;
19 |
20 | /**
21 | * 枚举: 1,0
22 | */
23 | private String required;
24 |
25 | }
26 |
--------------------------------------------------------------------------------
/src/main/java/com/liuzhihang/doc/view/integration/dto/YApiBodyForm.java:
--------------------------------------------------------------------------------
1 | package com.liuzhihang.doc.view.integration.dto;
2 |
3 | import lombok.Data;
4 |
5 | /**
6 | * @author liuzhihang
7 | * @date 2021/6/8 22:58
8 | */
9 | @Data
10 | public class YApiBodyForm {
11 |
12 | private String name;
13 |
14 | private String type;
15 |
16 | private String example;
17 |
18 | private String desc;
19 |
20 | /**
21 | * 枚举: 1,0
22 | */
23 | private String required;
24 |
25 | }
26 |
--------------------------------------------------------------------------------
/src/main/java/com/liuzhihang/doc/view/integration/dto/YApiHeader.java:
--------------------------------------------------------------------------------
1 | package com.liuzhihang.doc.view.integration.dto;
2 |
3 | import lombok.Data;
4 |
5 | /**
6 | * @author liuzhihang
7 | * @date 2021/6/8 22:58
8 | */
9 | @Data
10 | public class YApiHeader {
11 |
12 | private String name;
13 |
14 |
15 | private String example;
16 |
17 | private String desc;
18 | private String value;
19 |
20 | /**
21 | * 枚举: 1,0
22 | */
23 | private String required = "1";
24 |
25 | }
26 |
--------------------------------------------------------------------------------
/src/main/java/com/liuzhihang/doc/view/integration/dto/YuQueCreate.java:
--------------------------------------------------------------------------------
1 | package com.liuzhihang.doc.view.integration.dto;
2 |
3 | import lombok.Data;
4 |
5 | /**
6 | * 语雀创建文档
7 | *
8 | * https://www.yuque.com/yuque/developer/doc#63851c78
9 | *
10 | * 默认创建都是私密文档
11 | *
12 | * @author liuzhihang
13 | * @date 2022/4/1 22:54
14 | */
15 | @Data
16 | public class YuQueCreate {
17 |
18 | private String title;
19 |
20 | private String slug;
21 |
22 | private String format = "markdown";
23 |
24 | private String body;
25 | }
26 |
--------------------------------------------------------------------------------
/src/main/java/com/liuzhihang/doc/view/integration/dto/YuQueUpdate.java:
--------------------------------------------------------------------------------
1 | package com.liuzhihang.doc.view.integration.dto;
2 |
3 | import lombok.Data;
4 |
5 | /**
6 | * 语雀更新文档
7 | *
8 | * https://www.yuque.com/yuque/developer/doc#c2e9ee2a
9 | *
10 | * 默认创建都是私密文档
11 | *
12 | * @author liuzhihang
13 | * @date 2022/4/1 22:54
14 | */
15 | @Data
16 | public class YuQueUpdate {
17 |
18 | private String title;
19 |
20 | private String slug;
21 |
22 | private String body;
23 |
24 | private Integer _force_asl = 1;
25 |
26 | }
27 |
--------------------------------------------------------------------------------
/src/main/java/com/liuzhihang/doc/view/action/toolbar/AbstractToolbarUploadAction.java:
--------------------------------------------------------------------------------
1 | package com.liuzhihang.doc.view.action.toolbar;
2 |
3 | import com.liuzhihang.doc.view.action.upload.AbstractUploadAction;
4 | import com.liuzhihang.doc.view.service.DocViewUploadService;
5 |
6 | /**
7 | * @author liuzhihang
8 | * @date 2021/10/23 23:13
9 | */
10 | public abstract class AbstractToolbarUploadAction extends AbstractUploadAction {
11 |
12 | @Override
13 | protected DocViewUploadService uploadService() {
14 | return null;
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/src/main/java/com/liuzhihang/doc/view/constant/HeaderConstant.java:
--------------------------------------------------------------------------------
1 | package com.liuzhihang.doc.view.constant;
2 |
3 | /**
4 | * @author liuzhihang
5 | * @date 2020/3/6 13:27
6 | */
7 | public final class HeaderConstant {
8 |
9 | private HeaderConstant() {
10 | }
11 |
12 | public static final String APPLICATION_JSON = "application/json";
13 |
14 | public static final String APPLICATION_JSON_UTF8_VALUE = "application/json;charset=UTF-8";
15 |
16 |
17 | public static final String APPLICATION_FORM = "application/x-www-form-urlencoded";
18 |
19 | }
20 |
--------------------------------------------------------------------------------
/src/main/java/com/liuzhihang/doc/view/integration/dto/YApiCat.java:
--------------------------------------------------------------------------------
1 | package com.liuzhihang.doc.view.integration.dto;
2 |
3 | import com.google.gson.annotations.SerializedName;
4 | import lombok.Data;
5 |
6 | /**
7 | * 分组,菜单列表
8 | *
9 | * @author liuzhihang
10 | * @date 2021/6/8 23:19
11 | */
12 | @Data
13 | public class YApiCat {
14 |
15 | private String yapiUrl;
16 |
17 | private String token;
18 |
19 | @SerializedName("project_id")
20 | private Long projectId;
21 |
22 | @SerializedName("_id")
23 | private Long id;
24 |
25 | private String name;
26 |
27 | private String desc;
28 | }
29 |
--------------------------------------------------------------------------------
/src/main/java/com/liuzhihang/doc/view/dom/BeansDomElement.java:
--------------------------------------------------------------------------------
1 | package com.liuzhihang.doc.view.dom;
2 |
3 | import com.intellij.util.xml.DomElement;
4 | import com.intellij.util.xml.SubTagList;
5 |
6 | import java.util.List;
7 |
8 | /**
9 | * 解析 xml 将其中的 beans 标签映射为 BeansDomElement
10 | *
11 | * https://jetbrains.org/intellij/sdk/docs/reference_guide/frameworks_and_external_apis/xml_dom_api.html
12 | *
13 | * @author liuzhihang
14 | * @date 2022/4/11 23:40
15 | */
16 | public interface BeansDomElement extends DomElement {
17 |
18 | @SubTagList("dubbo:service")
19 | List getDubboServiceDomElements();
20 | }
21 |
--------------------------------------------------------------------------------
/src/main/java/com/liuzhihang/doc/view/utils/StorageUtils.java:
--------------------------------------------------------------------------------
1 | package com.liuzhihang.doc.view.utils;
2 |
3 | import com.intellij.openapi.project.Project;
4 | import com.intellij.project.ProjectKt;
5 |
6 | import java.nio.file.Path;
7 | import java.nio.file.Paths;
8 | import java.util.Objects;
9 |
10 | /**
11 | * @author liaozan
12 | * @since 2021/12/16
13 | */
14 | public class StorageUtils {
15 |
16 | public static Path getConfigDir(Project project) {
17 | Path configDir = ProjectKt.getStateStore(project).getDirectoryStorePath();
18 | return Paths.get(Objects.requireNonNull(configDir).toString(), "doc-view", "temp");
19 | }
20 |
21 | }
22 |
--------------------------------------------------------------------------------
/src/main/java/com/liuzhihang/doc/view/enums/ContentTypeEnum.java:
--------------------------------------------------------------------------------
1 | package com.liuzhihang.doc.view.enums;
2 |
3 | import lombok.Getter;
4 |
5 | /**
6 | * http 请求 content-type 枚举
7 | *
8 | * @author liuzhihang
9 | * @version ContentTypeEnum.java, v 0.1 2022年06月16日 8:38 PM liuzhihang
10 | */
11 | @Getter
12 | public enum ContentTypeEnum {
13 |
14 | JSON("Content-Type", "application/json"),
15 | FORM("Content-Type", "application/x-www-form-urlencoded"),
16 |
17 | ;
18 |
19 | ContentTypeEnum(String key, String value) {
20 | this.key = key;
21 | this.value = value;
22 | }
23 |
24 | private String key;
25 |
26 | private String value;
27 |
28 | }
--------------------------------------------------------------------------------
/src/main/java/com/liuzhihang/doc/view/dom/DubboServiceDomElement.java:
--------------------------------------------------------------------------------
1 | package com.liuzhihang.doc.view.dom;
2 |
3 | import com.intellij.util.xml.Attribute;
4 | import com.intellij.util.xml.DomElement;
5 | import com.intellij.util.xml.GenericAttributeValue;
6 | import com.intellij.util.xml.NameValue;
7 |
8 | /**
9 | * xml 配置中的 标签
10 | *
11 | * @author liuzhihang
12 | * @date 2022/4/11 23:54
13 | */
14 | public interface DubboServiceDomElement extends DomElement {
15 |
16 | /**
17 | * interface 属性, 就是接口的全路径
18 | *
19 | * @return
20 | */
21 | @NameValue
22 | @Attribute("interface")
23 | GenericAttributeValue getInterface();
24 | }
25 |
--------------------------------------------------------------------------------
/src/main/java/com/liuzhihang/doc/view/dto/Header.java:
--------------------------------------------------------------------------------
1 | package com.liuzhihang.doc.view.dto;
2 |
3 | import com.intellij.psi.PsiElement;
4 | import lombok.Data;
5 |
6 | /**
7 | * @author liuzhihang
8 | * @date 2020/2/28 10:40
9 | */
10 | @Data
11 | public class Header {
12 |
13 | /**
14 | * 节点
15 | */
16 | private PsiElement psiElement;
17 |
18 | /**
19 | * 是否必须 1必须 0非必须
20 | */
21 | private Boolean required;
22 | /**
23 | * 参数名
24 | */
25 | private String name;
26 |
27 | /**
28 | * 值
29 | */
30 | private String value;
31 |
32 | /**
33 | * 参数备注
34 | */
35 | private String desc;
36 |
37 |
38 | }
39 |
--------------------------------------------------------------------------------
/src/main/resources/icons/clearCash.svg:
--------------------------------------------------------------------------------
1 |
2 |
9 |
--------------------------------------------------------------------------------
/src/main/java/com/liuzhihang/doc/view/integration/ShowDocFacadeService.java:
--------------------------------------------------------------------------------
1 | package com.liuzhihang.doc.view.integration;
2 |
3 | import com.liuzhihang.doc.view.integration.dto.ShowDocUpdateRequest;
4 | import com.liuzhihang.doc.view.integration.dto.ShowDocUpdateResponse;
5 |
6 | /**
7 | * ShowDoc 文档对接
8 | *
9 | *
10 | * https://www.showdoc.com.cn/page/102098
11 | *
12 | * @author liuzhihang
13 | * @date 2021/7/27 12:43
14 | */
15 | public interface ShowDocFacadeService {
16 |
17 | /**
18 | * 上传到 ShowDoc
19 | *
20 | * @param request
21 | * @return
22 | */
23 | ShowDocUpdateResponse updateByApi(ShowDocUpdateRequest request) throws Exception;
24 |
25 | }
26 |
--------------------------------------------------------------------------------
/src/main/resources/icons/clearCash_dark.svg:
--------------------------------------------------------------------------------
1 |
2 |
9 |
--------------------------------------------------------------------------------
/src/main/java/com/liuzhihang/doc/view/ui/editor/EditorFloatingToolbarProvider.java:
--------------------------------------------------------------------------------
1 | package com.liuzhihang.doc.view.ui.editor;
2 |
3 | import com.intellij.openapi.editor.toolbar.floating.AbstractFloatingToolbarProvider;
4 | import org.jetbrains.annotations.NotNull;
5 |
6 | /**
7 | * @author liuzhihang
8 | * @version EditorWidgetActionProvider.java, v 0.1 2022/4/20 15:28 liuzhihan
9 | */
10 | public class EditorFloatingToolbarProvider extends AbstractFloatingToolbarProvider {
11 |
12 |
13 | public EditorFloatingToolbarProvider() {
14 | super("liuzhihang.doc.preview.editor.floating");
15 | }
16 |
17 | @Override
18 | public boolean getAutoHideable() {
19 | return true;
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/src/main/resources/icons/refresh.svg:
--------------------------------------------------------------------------------
1 |
2 |
8 |
--------------------------------------------------------------------------------
/src/main/resources/icons/refresh_dark.svg:
--------------------------------------------------------------------------------
1 |
2 |
8 |
--------------------------------------------------------------------------------
/src/main/resources/icons/editorPreview.svg:
--------------------------------------------------------------------------------
1 |
2 |
10 |
--------------------------------------------------------------------------------
/src/main/resources/icons/editorPreview_dark.svg:
--------------------------------------------------------------------------------
1 |
2 |
10 |
--------------------------------------------------------------------------------
/src/main/java/com/liuzhihang/doc/view/action/toolbar/window/WindowSettingsAction.java:
--------------------------------------------------------------------------------
1 | package com.liuzhihang.doc.view.action.toolbar.window;
2 |
3 | import com.intellij.openapi.actionSystem.AnAction;
4 | import com.intellij.openapi.actionSystem.AnActionEvent;
5 | import com.intellij.openapi.options.ShowSettingsUtil;
6 | import com.liuzhihang.doc.view.config.SettingsConfigurable;
7 | import org.jetbrains.annotations.NotNull;
8 |
9 | /**
10 | * @author liuzhihang
11 | * @date 2021/10/23 19:55
12 | */
13 | public class WindowSettingsAction extends AnAction {
14 |
15 | @Override
16 | public void actionPerformed(@NotNull AnActionEvent e) {
17 | ShowSettingsUtil.getInstance().showSettingsDialog(e.getProject(), SettingsConfigurable.class);
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/src/main/resources/icons/markdown.svg:
--------------------------------------------------------------------------------
1 |
2 |
9 |
--------------------------------------------------------------------------------
/src/main/resources/icons/markdown_dark.svg:
--------------------------------------------------------------------------------
1 |
2 |
9 |
--------------------------------------------------------------------------------
/src/main/java/com/liuzhihang/doc/view/constant/MethodConstant.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Ant Group
3 | * Copyright (c) 2004-2022 All Rights Reserved.
4 | */
5 | package com.liuzhihang.doc.view.constant;
6 |
7 | /**
8 | * 方法常量
9 | *
10 | * @author liuzhihang
11 | * @version MethodConstant.java, v 0.1 2022年06月17日 11:55 AM zijun.lzh
12 | */
13 | public final class MethodConstant {
14 |
15 | public static final String GET = "GET";
16 | public static final String POST = "POST";
17 | public static final String PUT = "PUT";
18 | public static final String DELETE = "DELETE";
19 | public static final String HEAD = "HEAD";
20 | public static final String OPTIONS = "OPTIONS";
21 | public static final String PATCH = "PATCH";
22 | public static final String DUBBO = "DUBBO";
23 |
24 | }
--------------------------------------------------------------------------------
/src/main/java/com/liuzhihang/doc/view/action/toolbar/window/WindowClearAction.java:
--------------------------------------------------------------------------------
1 | package com.liuzhihang.doc.view.action.toolbar.window;
2 |
3 | import com.intellij.openapi.actionSystem.AnAction;
4 | import com.intellij.openapi.actionSystem.AnActionEvent;
5 | import com.intellij.openapi.project.Project;
6 | import com.liuzhihang.doc.view.utils.CustomFileUtils;
7 | import org.jetbrains.annotations.NotNull;
8 |
9 | /**
10 | * @author liuzhihang
11 | * @date 2021/10/23 19:55
12 | */
13 | public class WindowClearAction extends AnAction {
14 |
15 | @Override
16 | public void actionPerformed(@NotNull AnActionEvent e) {
17 | Project project = e.getProject();
18 | if (project == null) {
19 | return;
20 | }
21 | CustomFileUtils.delete(project, "Doc View");
22 | }
23 |
24 | }
25 |
--------------------------------------------------------------------------------
/src/main/java/com/liuzhihang/doc/view/constant/DubboConstant.java:
--------------------------------------------------------------------------------
1 | package com.liuzhihang.doc.view.constant;
2 |
3 | import java.util.HashSet;
4 | import java.util.Set;
5 |
6 | /**
7 | * dubbo 相关常量
8 | *
9 | * @author liuzhihang
10 | * @date 2022/4/4 20:16
11 | */
12 | public class DubboConstant {
13 |
14 | /**
15 | * 包含类注解名称
16 | */
17 | public static Set SERVICE_ANNOTATIONS = new HashSet<>() {{
18 | add(DUBBO_SERVICE);
19 | add(SERVICE_1);
20 | add(SERVICE_2);
21 | }};
22 |
23 | public static final String DUBBO_SERVICE = "org.apache.dubbo.config.annotation.DubboService";
24 | public static final String SERVICE_1 = "org.apache.dubbo.config.annotation.Service";
25 | public static final String SERVICE_2 = "com.alibaba.dubbo.config.annotation.Service";
26 | }
27 |
--------------------------------------------------------------------------------
/src/main/java/com/liuzhihang/doc/view/provider/DocViewActionProvider.java:
--------------------------------------------------------------------------------
1 | package com.liuzhihang.doc.view.provider;
2 |
3 | /**
4 | * 编辑窗口,右上角
5 | *
6 | * @author liuzhihang
7 | * @since 2023/5/22 23:10
8 | */
9 | // public class DocViewActionProvider implements InspectionWidgetActionProvider {
10 | // @Nullable
11 | // @Override
12 | // public AnAction createAction(@NotNull Editor editor) {
13 | //
14 | // Project project = editor.getProject();
15 | // if (project == null || project.isDefault()) {
16 | // return null;
17 | // }
18 | //
19 | // return new AnAction("Refresh", "Refresh", AllIcons.Actions.Refresh) {
20 | // @Override
21 | // public void actionPerformed(@NotNull AnActionEvent e) {
22 | //
23 | // }
24 | // };
25 | // }
26 | // }
27 |
--------------------------------------------------------------------------------
/gradle.properties:
--------------------------------------------------------------------------------
1 | # Opt-out flag for bundling Kotlin standard library -> https://jb.gg/intellij-platform-kotlin-stdlib
2 | kotlin.stdlib.default.dependency=false
3 | # Enable Gradle Configuration Cache -> https://docs.gradle.org/current/userguide/configuration_cache.html
4 | org.gradle.configuration-cache=true
5 | # Enable Gradle Build Cache -> https://docs.gradle.org/current/userguide/build_cache.html
6 | org.gradle.caching=true
7 | # ????
8 | pluginGroup=com.liuzhihang.toolkit
9 | pluginName=Doc View
10 | pluginVersion=1.3.11
11 | pluginSinceBuild=241
12 | pluginUntilBuild=
13 | pluginDescription=parts/description.html
14 | platformType=IU
15 | platformVersion=2024.1
16 | # ,-Dide.browser.jcef.log.level=verbose,-Duser.language=en-US
17 | runIdeJvmArgs=-Dfile.encoding=utf-8
18 | # Gradle Releases -> https://github.com/gradle/gradle/releases
19 | gradleVersion=8.5
--------------------------------------------------------------------------------
/src/main/resources/icons/copy.svg:
--------------------------------------------------------------------------------
1 |
2 |
11 |
--------------------------------------------------------------------------------
/src/main/resources/icons/copy_dark.svg:
--------------------------------------------------------------------------------
1 |
2 |
11 |
--------------------------------------------------------------------------------
/src/main/java/com/liuzhihang/doc/view/DocViewBundle.java:
--------------------------------------------------------------------------------
1 | // Copyright 2000-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
2 | package com.liuzhihang.doc.view;
3 |
4 | import com.intellij.DynamicBundle;
5 | import org.jetbrains.annotations.NonNls;
6 | import org.jetbrains.annotations.NotNull;
7 | import org.jetbrains.annotations.PropertyKey;
8 |
9 | public final class DocViewBundle extends DynamicBundle {
10 |
11 | @NonNls
12 | private static final String BUNDLE = "messages.DocViewBundle";
13 | private static final DocViewBundle INSTANCE = new DocViewBundle();
14 |
15 | private DocViewBundle() {
16 | super(BUNDLE);
17 | }
18 |
19 | @NotNull
20 | public static String message(@NotNull @PropertyKey(resourceBundle = BUNDLE) String key, Object... params) {
21 | return INSTANCE.getMessage(key, params);
22 | }
23 | }
--------------------------------------------------------------------------------
/src/main/java/com/liuzhihang/doc/view/dto/Param.java:
--------------------------------------------------------------------------------
1 | package com.liuzhihang.doc.view.dto;
2 |
3 | import com.intellij.psi.PsiElement;
4 | import lombok.Data;
5 |
6 | /**
7 | * @author liuzhihang
8 | * @date 2020/2/27 16:39
9 | */
10 | @Data
11 | public class Param {
12 |
13 |
14 | /**
15 | * 参数的 psiElement
16 | */
17 | private PsiElement psiElement;
18 |
19 | /**
20 | * 是否必须
21 | */
22 | private Boolean required;
23 | /**
24 | * 参数名
25 | */
26 | private String name;
27 | /**
28 | * 参数示例
29 | */
30 | private String example;
31 |
32 | /**
33 | * 参数描述
34 | */
35 | private String desc;
36 |
37 | /**
38 | * 类型
39 | */
40 | private String type;
41 |
42 |
43 | /**
44 | * since
45 | */
46 | private String since;
47 |
48 | /**
49 | * version
50 | */
51 | private String version;
52 | }
53 |
--------------------------------------------------------------------------------
/src/main/java/com/liuzhihang/doc/view/action/toolbar/window/catalog/CatalogUploadYApiAction.java:
--------------------------------------------------------------------------------
1 | package com.liuzhihang.doc.view.action.toolbar.window.catalog;
2 |
3 | import com.intellij.openapi.actionSystem.AnActionEvent;
4 | import com.intellij.openapi.application.ApplicationManager;
5 | import com.liuzhihang.doc.view.service.DocViewUploadService;
6 | import com.liuzhihang.doc.view.service.impl.YApiServiceImpl;
7 | import org.jetbrains.annotations.NotNull;
8 |
9 | /**
10 | * @author liuzhihang
11 | * @date 2021/10/23 19:55
12 | */
13 | public class CatalogUploadYApiAction extends AbstractCatalogUploadAction {
14 |
15 | @Override
16 | public void actionPerformed(@NotNull AnActionEvent e) {
17 | super.actionPerformed(e);
18 | }
19 |
20 | @Override
21 | protected DocViewUploadService uploadService() {
22 | return ApplicationManager.getApplication().getService(YApiServiceImpl.class);
23 | }
24 |
25 | }
26 |
--------------------------------------------------------------------------------
/src/main/resources/icons/export.svg:
--------------------------------------------------------------------------------
1 |
2 |
8 |
--------------------------------------------------------------------------------
/src/main/java/com/liuzhihang/doc/view/action/toolbar/window/catalog/CatalogUploadYuQueAction.java:
--------------------------------------------------------------------------------
1 | package com.liuzhihang.doc.view.action.toolbar.window.catalog;
2 |
3 | import com.intellij.openapi.actionSystem.AnActionEvent;
4 | import com.intellij.openapi.application.ApplicationManager;
5 | import com.liuzhihang.doc.view.service.DocViewUploadService;
6 | import com.liuzhihang.doc.view.service.impl.YuQueServiceImpl;
7 | import org.jetbrains.annotations.NotNull;
8 |
9 | /**
10 | * @author liuzhihang
11 | * @date 2021/10/23 19:55
12 | */
13 | public class CatalogUploadYuQueAction extends AbstractCatalogUploadAction {
14 |
15 | @Override
16 | public void actionPerformed(@NotNull AnActionEvent e) {
17 | super.actionPerformed(e);
18 | }
19 |
20 | @Override
21 | protected DocViewUploadService uploadService() {
22 | return ApplicationManager.getApplication().getService(YuQueServiceImpl.class);
23 | }
24 |
25 | }
26 |
--------------------------------------------------------------------------------
/src/main/resources/icons/export_dark.svg:
--------------------------------------------------------------------------------
1 |
2 |
8 |
--------------------------------------------------------------------------------
/src/main/java/com/liuzhihang/doc/view/action/toolbar/window/catalog/CatalogUploadShowDocAction.java:
--------------------------------------------------------------------------------
1 | package com.liuzhihang.doc.view.action.toolbar.window.catalog;
2 |
3 | import com.intellij.openapi.actionSystem.AnActionEvent;
4 | import com.intellij.openapi.application.ApplicationManager;
5 | import com.liuzhihang.doc.view.service.DocViewUploadService;
6 | import com.liuzhihang.doc.view.service.impl.ShowDocServiceImpl;
7 | import org.jetbrains.annotations.NotNull;
8 |
9 | /**
10 | * @author liuzhihang
11 | * @date 2021/10/23 19:55
12 | */
13 | public class CatalogUploadShowDocAction extends AbstractCatalogUploadAction {
14 |
15 | @Override
16 | public void actionPerformed(@NotNull AnActionEvent e) {
17 | super.actionPerformed(e);
18 | }
19 |
20 | @Override
21 | protected DocViewUploadService uploadService() {
22 | return ApplicationManager.getApplication().getService(ShowDocServiceImpl.class);
23 | }
24 |
25 | }
26 |
--------------------------------------------------------------------------------
/src/main/resources/icons/httpAPI.svg:
--------------------------------------------------------------------------------
1 |
8 |
--------------------------------------------------------------------------------
/src/main/java/com/liuzhihang/doc/view/exception/DocViewException.java:
--------------------------------------------------------------------------------
1 | package com.liuzhihang.doc.view.exception;
2 |
3 | /**
4 | * DocView 异常类
5 | *
6 | * @author liuzhihang
7 | * @since 2023/8/5 17:13
8 | */
9 | public class DocViewException extends RuntimeException {
10 |
11 | /**
12 | * 空参构造
13 | */
14 | public DocViewException() {
15 | }
16 |
17 | /**
18 | * 消息构造器
19 | *
20 | * @param message 消息
21 | */
22 | public DocViewException(String message) {
23 | super(message);
24 | }
25 |
26 | /**
27 | * 堆栈 消息构造
28 | *
29 | * @param message 消息
30 | * @param cause 堆栈
31 | */
32 | public DocViewException(String message, Throwable cause) {
33 | super(message, cause);
34 | }
35 |
36 | /**
37 | * 堆栈
38 | *
39 | * @param cause 堆栈
40 | */
41 | public DocViewException(Throwable cause) {
42 | super(cause);
43 | }
44 |
45 | }
46 |
--------------------------------------------------------------------------------
/src/main/resources/icons/download.svg:
--------------------------------------------------------------------------------
1 |
2 |
10 |
--------------------------------------------------------------------------------
/src/main/resources/icons/download_dark.svg:
--------------------------------------------------------------------------------
1 |
2 |
10 |
--------------------------------------------------------------------------------
/src/main/java/com/liuzhihang/doc/view/ui/window/DocViewToolWindowFactory.java:
--------------------------------------------------------------------------------
1 | package com.liuzhihang.doc.view.ui.window;
2 |
3 | import com.intellij.openapi.project.DumbAware;
4 | import com.intellij.openapi.project.Project;
5 | import com.intellij.openapi.wm.ToolWindow;
6 | import com.intellij.openapi.wm.ToolWindowFactory;
7 | import com.intellij.ui.content.Content;
8 | import com.intellij.ui.content.ContentFactory;
9 | import org.jetbrains.annotations.NotNull;
10 |
11 | /**
12 | * @author liuzhihang
13 | * @date 2021/10/22 16:10
14 | */
15 | public class DocViewToolWindowFactory implements ToolWindowFactory, DumbAware {
16 | @Override
17 | public void createToolWindowContent(@NotNull Project project, @NotNull ToolWindow toolWindow) {
18 |
19 | ContentFactory contentFactory = ContentFactory.getInstance();
20 | Content content = contentFactory.createContent(new DocViewWindowPanel(project, toolWindow), "", false);
21 | toolWindow.getContentManager().addContent(content);
22 |
23 | }
24 |
25 | }
26 |
--------------------------------------------------------------------------------
/src/main/java/com/liuzhihang/doc/view/action/upload/YApiUploadAction.java:
--------------------------------------------------------------------------------
1 | package com.liuzhihang.doc.view.action.upload;
2 |
3 | import com.intellij.openapi.actionSystem.AnActionEvent;
4 | import com.intellij.openapi.application.ApplicationManager;
5 | import com.liuzhihang.doc.view.service.DocViewUploadService;
6 | import com.liuzhihang.doc.view.service.impl.YApiServiceImpl;
7 | import org.jetbrains.annotations.NotNull;
8 |
9 | /**
10 | * YApi 上传
11 | *
12 | * @author liuzhihang
13 | * @date 2021/6/8 16:40
14 | */
15 | public class YApiUploadAction extends AbstractUploadAction {
16 |
17 | @Override
18 | public void actionPerformed(@NotNull AnActionEvent e) {
19 | super.actionPerformed(e);
20 | }
21 |
22 | @Override
23 | protected DocViewUploadService uploadService() {
24 | return ApplicationManager.getApplication().getService(YApiServiceImpl.class);
25 | }
26 |
27 | @Override
28 | public void update(@NotNull AnActionEvent e) {
29 | super.update(e);
30 | }
31 |
32 |
33 | }
34 |
--------------------------------------------------------------------------------
/src/main/resources/icons/upload.svg:
--------------------------------------------------------------------------------
1 |
2 |
10 |
--------------------------------------------------------------------------------
/src/main/resources/icons/upload_dark.svg:
--------------------------------------------------------------------------------
1 |
2 |
10 |
--------------------------------------------------------------------------------
/src/main/java/com/liuzhihang/doc/view/utils/EditorUtils.java:
--------------------------------------------------------------------------------
1 | package com.liuzhihang.doc.view.utils;
2 |
3 | import com.intellij.lang.Language;
4 | import com.intellij.openapi.editor.EditorSettings;
5 | import com.intellij.openapi.editor.ex.EditorEx;
6 |
7 | /**
8 | * 编辑器工具
9 | *
10 | * @author liuzhihang
11 | * @since 2023/8/5 18:56
12 | */
13 | public class EditorUtils {
14 |
15 | /**
16 | * 对 markdown 编辑器进行渲染
17 | *
18 | * @param editor 编辑器
19 | */
20 | public static void renderMarkdownEditor(EditorEx editor) {
21 |
22 | EditorSettings editorSettings = editor.getSettings();
23 | editorSettings.setAdditionalLinesCount(0);
24 | editorSettings.setAdditionalColumnsCount(0);
25 | editorSettings.setLineMarkerAreaShown(false);
26 | editorSettings.setLineNumbersShown(false);
27 | editorSettings.setVirtualSpace(false);
28 | editorSettings.setFoldingOutlineShown(false);
29 |
30 | editorSettings.setLanguageSupplier(() -> Language.findLanguageByID("Markdown"));
31 |
32 | }
33 |
34 | }
35 |
--------------------------------------------------------------------------------
/src/main/java/com/liuzhihang/doc/view/integration/YApiFacadeService.java:
--------------------------------------------------------------------------------
1 | package com.liuzhihang.doc.view.integration;
2 |
3 | import com.liuzhihang.doc.view.integration.dto.YApiCat;
4 | import com.liuzhihang.doc.view.integration.dto.YapiSave;
5 |
6 | import java.util.List;
7 |
8 | /**
9 | * YApi 包装 service
10 | *
11 | * https://hellosean1025.github.io/yapi/openapi.html
12 | *
13 | * @author liuzhihang
14 | * @date 2021/6/8 19:20
15 | */
16 | public interface YApiFacadeService {
17 |
18 | /**
19 | * 新增接口
20 | *
21 | * @param dto
22 | */
23 | void save(YapiSave dto) throws Exception;
24 |
25 | /**
26 | * 获取菜单列表
27 | *
28 | * @param yapiUrl
29 | * @param projectId
30 | * @param token
31 | * @return
32 | * @throws Exception
33 | */
34 | List getCatMenu(String yapiUrl, Long projectId, String token) throws Exception;
35 |
36 | /**
37 | * 添加菜单
38 | *
39 | * @param cat
40 | * @return
41 | * @throws Exception
42 | */
43 | YApiCat addCat(YApiCat cat) throws Exception;
44 | }
45 |
--------------------------------------------------------------------------------
/src/main/java/com/liuzhihang/doc/view/action/PreviewAction.java:
--------------------------------------------------------------------------------
1 | package com.liuzhihang.doc.view.action;
2 |
3 | import com.intellij.openapi.actionSystem.ActionUpdateThread;
4 | import com.intellij.openapi.actionSystem.AnAction;
5 | import com.intellij.openapi.actionSystem.AnActionEvent;
6 | import com.liuzhihang.doc.view.ui.PreviewForm;
7 | import org.jetbrains.annotations.NotNull;
8 |
9 | /**
10 | * 单个类或者方法中操作
11 | *
12 | * @author liuzhihang
13 | * @date 2020/2/26 21:57
14 | */
15 | public class PreviewAction extends AbstractAction {
16 |
17 | /**
18 | * @see AnAction#actionPerformed(AnActionEvent)
19 | */
20 | @Override
21 | public void actionPerformed(AnActionEvent e) {
22 | // 先执行抽象类逻辑
23 | super.actionPerformed(e);
24 |
25 | // 预览文档
26 | PreviewForm.getInstance(targetClass, targetMethod).popup();
27 | }
28 |
29 | /**
30 | * @see AnAction#update(AnActionEvent)
31 | */
32 | @Override
33 | public @NotNull ActionUpdateThread getActionUpdateThread() {
34 | return ActionUpdateThread.BGT;
35 | }
36 |
37 | }
38 |
--------------------------------------------------------------------------------
/src/main/java/com/liuzhihang/doc/view/dom/BeansDescription.java:
--------------------------------------------------------------------------------
1 | package com.liuzhihang.doc.view.dom;
2 |
3 | import com.intellij.openapi.module.Module;
4 | import com.intellij.psi.xml.XmlFile;
5 | import com.intellij.psi.xml.XmlTag;
6 | import com.intellij.util.xml.DomFileDescription;
7 | import org.jetbrains.annotations.NotNull;
8 | import org.jetbrains.annotations.Nullable;
9 |
10 | /**
11 | * @author liuzhihang
12 | * @link https://jetbrains.org/intellij/sdk/docs/reference_guide/frameworks_and_external_apis/xml_dom_api.html
13 | * @date 2022-04-11 23:49:37
14 | */
15 | public class BeansDescription extends DomFileDescription {
16 |
17 | public BeansDescription() {
18 | super(BeansDomElement.class, "beans");
19 | }
20 |
21 | @Override
22 | public boolean isMyFile(@NotNull XmlFile file, @Nullable Module module) {
23 | XmlTag rootTag = file.getRootTag();
24 | return rootTag != null && rootTag.getName().equals(getRootTagName());
25 | }
26 |
27 | @Override
28 | public boolean acceptsOtherRootTagNames() {
29 | return true;
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/src/main/java/com/liuzhihang/doc/view/action/upload/YuQueUploadAction.java:
--------------------------------------------------------------------------------
1 | package com.liuzhihang.doc.view.action.upload;
2 |
3 | import com.intellij.openapi.actionSystem.AnActionEvent;
4 | import com.intellij.openapi.application.ApplicationManager;
5 | import com.liuzhihang.doc.view.service.DocViewUploadService;
6 | import com.liuzhihang.doc.view.service.impl.YuQueServiceImpl;
7 | import org.jetbrains.annotations.NotNull;
8 |
9 | /**
10 | * 语雀 上传
11 | *
12 | * @author liuzhihang
13 | * @date 2021/6/8 16:40
14 | */
15 | public class YuQueUploadAction extends AbstractUploadAction {
16 |
17 | @Override
18 | public void actionPerformed(@NotNull AnActionEvent e) {
19 | super.actionPerformed(e);
20 | }
21 |
22 | @Override
23 | protected DocViewUploadService uploadService() {
24 | return ApplicationManager.getApplication().getService(YuQueServiceImpl.class);
25 | }
26 |
27 | /**
28 | * 设置右键菜单是否隐藏 上传按钮
29 | *
30 | * @param e
31 | */
32 | @Override
33 | public void update(@NotNull AnActionEvent e) {
34 | super.update(e);
35 | }
36 |
37 | }
38 |
--------------------------------------------------------------------------------
/src/main/java/com/liuzhihang/doc/view/action/upload/ShowDocUploadAction.java:
--------------------------------------------------------------------------------
1 | package com.liuzhihang.doc.view.action.upload;
2 |
3 | import com.intellij.openapi.actionSystem.AnActionEvent;
4 | import com.intellij.openapi.application.ApplicationManager;
5 | import com.liuzhihang.doc.view.service.DocViewUploadService;
6 | import com.liuzhihang.doc.view.service.impl.ShowDocServiceImpl;
7 | import org.jetbrains.annotations.NotNull;
8 |
9 | /**
10 | * YApi 上传
11 | *
12 | * @author liuzhihang
13 | * @date 2021/6/8 16:40
14 | */
15 | public class ShowDocUploadAction extends AbstractUploadAction {
16 |
17 | @Override
18 | public void actionPerformed(@NotNull AnActionEvent e) {
19 | super.actionPerformed(e);
20 | }
21 |
22 | @Override
23 | protected DocViewUploadService uploadService() {
24 | return ApplicationManager.getApplication().getService(ShowDocServiceImpl.class);
25 | }
26 |
27 | /**
28 | * 设置右键菜单是否隐藏 上传按钮
29 | *
30 | * @param e
31 | */
32 | @Override
33 | public void update(@NotNull AnActionEvent e) {
34 | super.update(e);
35 | }
36 |
37 | }
38 |
--------------------------------------------------------------------------------
/src/main/resources/META-INF/pluginIcon.svg:
--------------------------------------------------------------------------------
1 |
3 |
--------------------------------------------------------------------------------
/src/main/java/com/liuzhihang/doc/view/utils/SpringHeaderUtils.java:
--------------------------------------------------------------------------------
1 | package com.liuzhihang.doc.view.utils;
2 |
3 | import com.liuzhihang.doc.view.constant.HeaderConstant;
4 | import com.liuzhihang.doc.view.dto.Header;
5 | import org.jetbrains.annotations.NotNull;
6 |
7 | /**
8 | * @author liuzhihang
9 | * @date 2020/3/6 13:24
10 | */
11 | public class SpringHeaderUtils {
12 |
13 | @NotNull
14 | public static Header buildJsonHeader() {
15 |
16 | Header header = new Header();
17 | header.setRequired(true);
18 | header.setName("Content-Type");
19 | header.setValue(HeaderConstant.APPLICATION_JSON);
20 | header.setDesc(HeaderConstant.APPLICATION_JSON);
21 |
22 |
23 | return header;
24 | }
25 |
26 | @NotNull
27 | public static Header buildFormHeader() {
28 |
29 | Header header = new Header();
30 | header.setRequired(true);
31 | header.setName("Content-Type");
32 | header.setValue(HeaderConstant.APPLICATION_FORM);
33 | header.setDesc(HeaderConstant.APPLICATION_FORM);
34 |
35 |
36 | return header;
37 | }
38 |
39 | }
40 |
--------------------------------------------------------------------------------
/parts/description.html:
--------------------------------------------------------------------------------
1 |
2 | Generate Markdown documents based on the interface
3 |
4 | GitHub |
5 | Issues |
6 | Website |
7 | LICENSE
8 |
9 |
10 |
11 |
12 | English introduction
13 |
14 |
15 |
16 | The Markdown document is generated based on the interface and can be previewed, edited, and uploaded to YApi or ShowDoc.
17 |
18 |
19 |
20 |
21 | - Supports separate display of parameter classes
22 |
23 |
24 |
25 |
26 | 中文介绍
27 |
28 |
29 |
30 | 基于接口生成 Markdown 文档, 支持预览、编辑以及上传到YApi、ShowDoc、语雀。
31 |
32 |
33 |
36 |
37 |
38 | Other
39 |
40 |
41 |
42 | - 个人公众号: 『 程序员小航 』
43 |
44 | - 小伙伴们如果有遇到问题或者有使用建议,可以关注公众号并留言。
45 |
46 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2019 liuzhihang
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/src/main/java/com/liuzhihang/doc/view/action/toolbar/window/WindowCollapseAction.java:
--------------------------------------------------------------------------------
1 | package com.liuzhihang.doc.view.action.toolbar.window;
2 |
3 | import com.intellij.openapi.actionSystem.AnAction;
4 | import com.intellij.openapi.actionSystem.AnActionEvent;
5 | import com.intellij.openapi.actionSystem.PlatformDataKeys;
6 | import com.intellij.openapi.project.Project;
7 | import com.intellij.ui.TreeExpandCollapse;
8 | import com.intellij.ui.treeStructure.SimpleTree;
9 | import com.liuzhihang.doc.view.data.DocViewDataKeys;
10 | import org.jetbrains.annotations.NotNull;
11 |
12 | /**
13 | * @author liuzhihang
14 | * @date 2021/10/23 19:55
15 | */
16 | public class WindowCollapseAction extends AnAction {
17 |
18 | @Override
19 | public void actionPerformed(@NotNull AnActionEvent e) {
20 | // 获取当前project对象
21 | Project project = e.getData(PlatformDataKeys.PROJECT);
22 | SimpleTree catalogTree = e.getData(DocViewDataKeys.WINDOW_CATALOG_TREE);
23 |
24 | if (catalogTree == null || project == null) {
25 | return;
26 | }
27 | TreeExpandCollapse.collapse(catalogTree);
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/src/main/java/com/liuzhihang/doc/view/action/toolbar/window/WindowExpandAction.java:
--------------------------------------------------------------------------------
1 | package com.liuzhihang.doc.view.action.toolbar.window;
2 |
3 | import com.intellij.openapi.actionSystem.AnAction;
4 | import com.intellij.openapi.actionSystem.AnActionEvent;
5 | import com.intellij.openapi.actionSystem.PlatformDataKeys;
6 | import com.intellij.openapi.project.Project;
7 | import com.intellij.ui.TreeExpandCollapse;
8 | import com.intellij.ui.treeStructure.SimpleTree;
9 | import com.liuzhihang.doc.view.data.DocViewDataKeys;
10 | import org.jetbrains.annotations.NotNull;
11 |
12 | /**
13 | * @author liuzhihang
14 | * @date 2021/10/23 19:55
15 | */
16 | public class WindowExpandAction extends AnAction {
17 |
18 | @Override
19 | public void actionPerformed(@NotNull AnActionEvent e) {
20 | // 获取当前project对象
21 | Project project = e.getData(PlatformDataKeys.PROJECT);
22 | SimpleTree catalogTree = e.getData(DocViewDataKeys.WINDOW_CATALOG_TREE);
23 |
24 | if (catalogTree == null || project == null) {
25 | return;
26 | }
27 | TreeExpandCollapse.expandAll(catalogTree);
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/src/main/java/com/liuzhihang/doc/view/utils/DialogUtil.java:
--------------------------------------------------------------------------------
1 | package com.liuzhihang.doc.view.utils;
2 |
3 | import com.intellij.openapi.ui.DialogWrapper;
4 | import org.jetbrains.annotations.Nullable;
5 |
6 | import javax.swing.*;
7 | import java.awt.*;
8 |
9 | /**
10 | * 弹出式提示工具类
11 | *
12 | * @author lvgorice@gmail.com
13 | * @version 1.0
14 | * @date 2020-11-20
15 | */
16 | public class DialogUtil extends DialogWrapper {
17 |
18 | private final String message;
19 |
20 | private DialogUtil(String title, String message) {
21 | super(true); // use current window as parent
22 | this.message = message;
23 | init();
24 | setTitle(title);
25 | }
26 |
27 | @Nullable
28 | @Override
29 | protected JComponent createCenterPanel() {
30 | JPanel dialogPanel = new JPanel(new BorderLayout());
31 |
32 | JLabel label = new JLabel(message);
33 | dialogPanel.add(label, BorderLayout.CENTER);
34 |
35 | return dialogPanel;
36 | }
37 |
38 | public static boolean confirm(String title, String message) {
39 | return new DialogUtil(title, message).showAndGet();
40 | }
41 | }
--------------------------------------------------------------------------------
/src/main/resources/icons/httpAPI_dark.svg:
--------------------------------------------------------------------------------
1 |
15 |
--------------------------------------------------------------------------------
/src/main/java/com/liuzhihang/doc/view/constant/SwaggerConstant.java:
--------------------------------------------------------------------------------
1 | package com.liuzhihang.doc.view.constant;
2 |
3 | /**
4 | * @author liuzhihang
5 | * @date 2021/6/10 19:01
6 | */
7 | public final class SwaggerConstant {
8 |
9 | private SwaggerConstant() {
10 | }
11 |
12 | /**
13 | * Swagger 2.x 配置
14 | */
15 | public static final String API_MODEL = "io.swagger.annotations.ApiModel";
16 | public static final String API_MODEL_PROPERTY = "io.swagger.annotations.ApiModelProperty";
17 | public static final String API = "io.swagger.annotations.Api";
18 | public static final String API_OPERATION = "io.swagger.annotations.ApiOperation";
19 | public static final String API_PARAM = "io.swagger.annotations.ApiParam";
20 |
21 |
22 | /**
23 | * Swagger 3 配置
24 | */
25 | public static final String TAG = "io.swagger.v3.oas.annotations.tags.Tag";
26 | public static final String OPERATION = "io.swagger.v3.oas.annotations.Operation";
27 | public static final String PARAMETER = "io.swagger.v3.oas.annotations.Parameter";
28 | public static final String PARAMETERS = "io.swagger.v3.oas.annotations.Parameters";
29 | public static final String SCHEMA = "io.swagger.v3.oas.annotations.media.Schema";
30 | }
31 |
--------------------------------------------------------------------------------
/src/main/java/com/liuzhihang/doc/view/ui/window/DocViewNode.java:
--------------------------------------------------------------------------------
1 | package com.liuzhihang.doc.view.ui.window;
2 |
3 | import com.intellij.openapi.project.Project;
4 | import com.intellij.ui.treeStructure.CachingSimpleNode;
5 | import com.intellij.ui.treeStructure.SimpleNode;
6 | import com.liuzhihang.doc.view.dto.DocView;
7 |
8 | import java.util.List;
9 |
10 | /**
11 | * @author liuzhihang
12 | * @date 2022/4/5 16:05
13 | */
14 | public abstract class DocViewNode extends CachingSimpleNode {
15 |
16 | protected DocViewNode(SimpleNode parentNode) {
17 | super(parentNode);
18 |
19 | }
20 |
21 | @Override
22 | protected abstract SimpleNode[] buildChildren();
23 |
24 | @Override
25 | public String getName() {
26 | return "Doc View";
27 | }
28 |
29 | public abstract List docViewList();
30 |
31 | public abstract void updateNode(Project project);
32 |
33 | /**
34 | * 生成的文档保存路径
35 | *
36 | * @param project project
37 | * @return path
38 | */
39 | public abstract String docPath(Project project);
40 |
41 | /**
42 | * 生成的 .http 文件路径
43 | *
44 | * @param project project
45 | * @return path
46 | */
47 | public abstract String httpPath(Project project);
48 |
49 | }
50 |
--------------------------------------------------------------------------------
/src/main/resources/icons/pin.svg:
--------------------------------------------------------------------------------
1 |
2 |
8 |
--------------------------------------------------------------------------------
/src/main/resources/icons/pin_dark.svg:
--------------------------------------------------------------------------------
1 |
2 |
8 |
--------------------------------------------------------------------------------
/src/main/java/com/liuzhihang/doc/view/config/YApiSettings.java:
--------------------------------------------------------------------------------
1 | package com.liuzhihang.doc.view.config;
2 |
3 | import com.intellij.openapi.components.PersistentStateComponent;
4 | import com.intellij.openapi.components.State;
5 | import com.intellij.openapi.components.Storage;
6 | import com.intellij.openapi.project.Project;
7 | import com.intellij.util.xmlb.XmlSerializerUtil;
8 | import lombok.Data;
9 | import org.jetbrains.annotations.NotNull;
10 | import org.jetbrains.annotations.Nullable;
11 |
12 | /**
13 | * YApi 的相关设置
14 | *
15 | * @author liuzhihang
16 | * @date 2020/11/22 13:51
17 | */
18 | @Data
19 | @State(name = "DocViewYApiSettingsComment", storages = {@Storage("DocViewYApiSettings.xml")})
20 | public class YApiSettings implements PersistentStateComponent {
21 |
22 | private String url;
23 |
24 | private Long projectId;
25 |
26 | private String token;
27 |
28 | public static YApiSettings getInstance(@NotNull Project project) {
29 | return project.getService(YApiSettings.class);
30 | }
31 |
32 | @Override
33 | public @Nullable
34 | YApiSettings getState() {
35 | return this;
36 | }
37 |
38 | @Override
39 | public void loadState(@NotNull YApiSettings state) {
40 |
41 | XmlSerializerUtil.copyBean(state, this);
42 | }
43 |
44 | }
45 |
--------------------------------------------------------------------------------
/src/main/java/com/liuzhihang/doc/view/integration/dto/ShowDocUpdateResponse.java:
--------------------------------------------------------------------------------
1 | package com.liuzhihang.doc.view.integration.dto;
2 |
3 | import com.google.gson.annotations.SerializedName;
4 | import lombok.Data;
5 |
6 | /**
7 | * @author liuzhihang
8 | * @date 2021/7/27 11:45
9 | */
10 | @Data
11 | public class ShowDocUpdateResponse {
12 |
13 | @SerializedName("error_code")
14 | private String errorCode;
15 | private DataInner data;
16 |
17 | @Data
18 | public static class DataInner {
19 |
20 | @SerializedName("s_number")
21 | private String sNumber;
22 |
23 | @SerializedName("page_title")
24 | private String pageTitle;
25 |
26 | @SerializedName("page_id")
27 | private String pageId;
28 |
29 | @SerializedName("page_content")
30 | private String pageContent;
31 |
32 | @SerializedName("page_comments")
33 | private String pageComments;
34 |
35 | @SerializedName("item_id")
36 | private String itemId;
37 |
38 | @SerializedName("cat_id")
39 | private String catId;
40 |
41 | @SerializedName("author_username")
42 | private String authorUsername;
43 |
44 | @SerializedName("author_uid")
45 | private String authorUid;
46 |
47 | private String addtime;
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/src/main/java/com/liuzhihang/doc/view/config/ShowDocSettings.java:
--------------------------------------------------------------------------------
1 | package com.liuzhihang.doc.view.config;
2 |
3 | import com.intellij.openapi.components.PersistentStateComponent;
4 | import com.intellij.openapi.components.State;
5 | import com.intellij.openapi.components.Storage;
6 | import com.intellij.openapi.project.Project;
7 | import com.intellij.util.xmlb.XmlSerializerUtil;
8 | import lombok.Data;
9 | import org.jetbrains.annotations.NotNull;
10 | import org.jetbrains.annotations.Nullable;
11 |
12 | /**
13 | * ShowDoc 的相关设置
14 | *
15 | * @author liuzhihang
16 | * @date 2020/11/22 13:51
17 | */
18 | @Data
19 | @State(name = "DocViewShowDocSettingsComment", storages = {@Storage("DocViewShowDocSettings.xml")})
20 | public class ShowDocSettings implements PersistentStateComponent {
21 |
22 | private String url;
23 |
24 | private String apiKey;
25 |
26 | private String apiToken;
27 |
28 |
29 | public static ShowDocSettings getInstance(@NotNull Project project) {
30 | return project.getService(ShowDocSettings.class);
31 | }
32 |
33 | @Override
34 | public @Nullable
35 | ShowDocSettings getState() {
36 | return this;
37 | }
38 |
39 | @Override
40 | public void loadState(@NotNull ShowDocSettings state) {
41 |
42 | XmlSerializerUtil.copyBean(state, this);
43 | }
44 |
45 | }
46 |
--------------------------------------------------------------------------------
/src/main/java/com/liuzhihang/doc/view/integration/dto/ShowDocUpdateRequest.java:
--------------------------------------------------------------------------------
1 | package com.liuzhihang.doc.view.integration.dto;
2 |
3 | import com.google.gson.annotations.SerializedName;
4 | import lombok.Data;
5 |
6 | /**
7 | * @author liuzhihang
8 | * @date 2021/7/27 11:45
9 | */
10 | @Data
11 | public class ShowDocUpdateRequest {
12 |
13 | /**
14 | * 请求地址
15 | */
16 | private String showDocUrl;
17 |
18 | /**
19 | * api_key,认证凭证。登录showdoc,进入具体项目后,点击右上角的”项目设置”-“开放API”便可看到
20 | */
21 | @SerializedName("api_key")
22 | private String apiKey;
23 |
24 | /**
25 | * 同上
26 | */
27 | @SerializedName("api_token")
28 | private String apiToken;
29 |
30 | /**
31 | * 可选参数。当页面文档处于目录下时,请传递目录名。当目录名不存在时,showdoc会自动创建此目录。
32 | * 需要创建多层目录的时候请用斜杆隔开,例如 “一层/二层/三层”
33 | */
34 | @SerializedName("cat_name")
35 | private String catName;
36 |
37 | /**
38 | * 页面标题。请保证其唯一。
39 | * (或者,当页面处于目录下时,请保证页面标题在该目录下唯一)。
40 | * 当页面标题不存在时,showdoc将会创建此页面。当页面标题存在时,将用page_content更新其内容
41 | */
42 | @SerializedName("page_title")
43 | private String pageTitle;
44 |
45 | /**
46 | * 页面内容,可传递markdown格式的文本或者html源码
47 | */
48 | @SerializedName("page_content")
49 | private String pageContent;
50 |
51 | /**
52 | * 可选,页面序号。默认是99。数字越小,该页面越靠前
53 | */
54 | @SerializedName("s_number")
55 | private Long sNumber;
56 |
57 |
58 | }
59 |
--------------------------------------------------------------------------------
/src/main/java/com/liuzhihang/doc/view/action/upload/AbstractUploadAction.java:
--------------------------------------------------------------------------------
1 | package com.liuzhihang.doc.view.action.upload;
2 |
3 | import com.intellij.openapi.actionSystem.ActionUpdateThread;
4 | import com.intellij.openapi.actionSystem.AnAction;
5 | import com.intellij.openapi.actionSystem.AnActionEvent;
6 | import com.liuzhihang.doc.view.action.AbstractAction;
7 | import com.liuzhihang.doc.view.dto.DocView;
8 | import com.liuzhihang.doc.view.service.DocViewService;
9 | import com.liuzhihang.doc.view.service.DocViewUploadService;
10 | import org.jetbrains.annotations.NotNull;
11 |
12 | import java.util.List;
13 |
14 | /**
15 | * @author liuzhihang
16 | * @date 2021/10/23 23:13
17 | */
18 | public abstract class AbstractUploadAction extends AbstractAction {
19 |
20 | /**
21 | * @see AnAction#actionPerformed(AnActionEvent)
22 | */
23 | public void actionPerformed(@NotNull AnActionEvent e) {
24 | // 先执行抽象类逻辑
25 | super.actionPerformed(e);
26 |
27 | List docViewList = DocViewService.getInstance(project, targetClass).buildDoc(targetClass, targetMethod);
28 |
29 | // 上传
30 | uploadService().upload(project, docViewList);
31 |
32 | }
33 |
34 | /**
35 | * 具体上传服务
36 | */
37 | protected abstract DocViewUploadService uploadService();
38 |
39 | @Override
40 | public @NotNull ActionUpdateThread getActionUpdateThread() {
41 | return ActionUpdateThread.BGT;
42 | }
43 |
44 | }
45 |
--------------------------------------------------------------------------------
/src/main/java/com/liuzhihang/doc/view/action/toolbar/window/catalog/AbstractCatalogUploadAction.java:
--------------------------------------------------------------------------------
1 | package com.liuzhihang.doc.view.action.toolbar.window.catalog;
2 |
3 | import com.intellij.openapi.actionSystem.AnActionEvent;
4 | import com.intellij.openapi.actionSystem.PlatformDataKeys;
5 | import com.intellij.openapi.project.Project;
6 | import com.intellij.ui.treeStructure.SimpleNode;
7 | import com.intellij.ui.treeStructure.SimpleTree;
8 | import com.liuzhihang.doc.view.action.upload.AbstractUploadAction;
9 | import com.liuzhihang.doc.view.data.DocViewDataKeys;
10 | import com.liuzhihang.doc.view.ui.window.DocViewNode;
11 | import org.jetbrains.annotations.NotNull;
12 |
13 | /**
14 | * @author liuzhihang
15 | * @date 2021/10/23 23:13
16 | */
17 | public abstract class AbstractCatalogUploadAction extends AbstractUploadAction {
18 |
19 | protected Project project;
20 |
21 | @Override
22 | public void actionPerformed(@NotNull AnActionEvent e) {
23 |
24 | // 获取当前project对象
25 | project = e.getData(PlatformDataKeys.PROJECT);
26 | SimpleTree simpleTree = e.getData(DocViewDataKeys.WINDOW_CATALOG_TREE);
27 |
28 | if (simpleTree == null || project == null) {
29 | return;
30 | }
31 |
32 | SimpleNode selectedNode = simpleTree.getSelectedNode();
33 |
34 | if (selectedNode instanceof DocViewNode docViewNode) {
35 | uploadService().upload(project, docViewNode.docViewList());
36 | }
37 | }
38 |
39 | }
40 |
--------------------------------------------------------------------------------
/src/main/java/com/liuzhihang/doc/view/dto/Body.java:
--------------------------------------------------------------------------------
1 | package com.liuzhihang.doc.view.dto;
2 |
3 |
4 | import com.intellij.psi.PsiElement;
5 | import lombok.Getter;
6 | import lombok.Setter;
7 |
8 | import java.util.LinkedList;
9 | import java.util.List;
10 |
11 | /**
12 | * @author liuzhihang
13 | * @date 2020/2/27 16:39
14 | */
15 | @Getter
16 | @Setter
17 | public class Body {
18 |
19 | /**
20 | * 参数的 psiElement
21 | */
22 | private PsiElement psiElement;
23 |
24 | /**
25 | * 是否必须
26 | */
27 | private Boolean required;
28 | /**
29 | * 参数名
30 | */
31 | private String name;
32 | /**
33 | * 参数示例
34 | */
35 | private String example;
36 |
37 | /**
38 | * 参数描述
39 | */
40 | private String desc;
41 |
42 | /**
43 | * 类型
44 | */
45 | private String type;
46 |
47 | /**
48 | * since
49 | */
50 | private String since;
51 |
52 | /**
53 | * version
54 | */
55 | private String version;
56 |
57 | /**
58 | * 初始化时创建集合
59 | */
60 | private List childList = new LinkedList<>();
61 |
62 | private Body parent;
63 |
64 | /**
65 | * 当类型是类时, 全路径
66 | * 如果是 HashMap 则是内部泛型的类型
67 | */
68 | private String qualifiedNameForClassType;
69 |
70 | /**
71 | * 是否是集合
72 | */
73 | private boolean isCollection = false;
74 |
75 | /**
76 | * 是否是 map
77 | */
78 | private boolean isMap = false;
79 |
80 | }
81 |
--------------------------------------------------------------------------------
/src/main/java/com/liuzhihang/doc/view/config/ApplicationSettings.java:
--------------------------------------------------------------------------------
1 | package com.liuzhihang.doc.view.config;
2 |
3 | import com.intellij.openapi.components.PersistentStateComponent;
4 | import com.intellij.openapi.components.State;
5 | import com.intellij.openapi.components.Storage;
6 | import com.intellij.openapi.project.Project;
7 | import com.intellij.util.xmlb.XmlSerializerUtil;
8 | import lombok.Data;
9 | import org.jetbrains.annotations.NotNull;
10 | import org.jetbrains.annotations.Nullable;
11 |
12 | /**
13 | * 项目级的持久配置
14 | *
15 | *
16 | * See IntelliJ Platform SDK DevGuide
17 | *
18 | * @author liuzhihang
19 | * @date 2020/2/27 19:02
20 | */
21 | @Data
22 | @State(name = "DocViewApplicationSettingsComponent", storages = {@Storage("DocViewApplicationSettings.xml")})
23 | public class ApplicationSettings implements PersistentStateComponent {
24 |
25 | private String pluginVersion = "0.0.1";
26 |
27 |
28 | public static ApplicationSettings getInstance(@NotNull Project project) {
29 | return project.getService(ApplicationSettings.class);
30 | }
31 |
32 |
33 | @Nullable
34 | @Override
35 | public ApplicationSettings getState() {
36 | return this;
37 | }
38 |
39 | @Override
40 | public void loadState(@NotNull ApplicationSettings state) {
41 | XmlSerializerUtil.copyBean(state, this);
42 | }
43 |
44 |
45 | }
46 |
--------------------------------------------------------------------------------
/src/main/java/com/liuzhihang/doc/view/action/toolbar/preview/PreviewRightExportAction.java:
--------------------------------------------------------------------------------
1 | package com.liuzhihang.doc.view.action.toolbar.preview;
2 |
3 | import com.intellij.openapi.actionSystem.AnAction;
4 | import com.intellij.openapi.actionSystem.AnActionEvent;
5 | import com.intellij.openapi.actionSystem.PlatformDataKeys;
6 | import com.intellij.openapi.project.Project;
7 | import com.intellij.openapi.ui.popup.JBPopup;
8 | import com.liuzhihang.doc.view.data.DocViewDataKeys;
9 | import com.liuzhihang.doc.view.dto.DocView;
10 | import com.liuzhihang.doc.view.utils.ExportUtils;
11 | import org.jetbrains.annotations.NotNull;
12 |
13 | /**
14 | * Preview 右侧单个导出
15 | *
16 | * @author liuzhihang
17 | * @date 2021/10/23 22:31
18 | */
19 | public class PreviewRightExportAction extends AnAction {
20 | @Override
21 | public void actionPerformed(@NotNull AnActionEvent e) {
22 |
23 | // 获取当前project对象
24 | Project project = e.getData(PlatformDataKeys.PROJECT);
25 | JBPopup popup = e.getData(DocViewDataKeys.PREVIEW_POPUP);
26 | DocView currentDocView = e.getData(DocViewDataKeys.PREVIEW_CURRENT_DOC_VIEW);
27 | String currentMarkdownText = e.getData(DocViewDataKeys.PREVIEW_MARKDOWN_TEXT);
28 |
29 | if (popup == null || project == null || currentDocView == null || currentMarkdownText == null) {
30 | return;
31 | }
32 | popup.cancel();
33 | ExportUtils.exportMarkdown(project, currentDocView.getName(), currentMarkdownText);
34 | }
35 |
36 | }
37 |
--------------------------------------------------------------------------------
/src/main/java/com/liuzhihang/doc/view/dto/DocViewParamData.java:
--------------------------------------------------------------------------------
1 | package com.liuzhihang.doc.view.dto;
2 |
3 | import com.intellij.psi.PsiElement;
4 | import lombok.Data;
5 |
6 | import java.util.ArrayList;
7 | import java.util.List;
8 |
9 | /**
10 | * 参数 data 数据
11 | *
12 | * @author liuzhihang
13 | * @date 2020/2/27 16:39
14 | */
15 | @Data
16 | public class DocViewParamData {
17 |
18 | /**
19 | * 参数的 psiElement
20 | */
21 | private PsiElement psiElement;
22 |
23 | /**
24 | * 前缀 1
25 | */
26 | private String prefixSymbol1 = "";
27 |
28 | /**
29 | * 前缀 2
30 | */
31 | private String prefixSymbol2 = "";
32 |
33 | /**
34 | * 参数名
35 | */
36 | private String name;
37 |
38 | /**
39 | * 类型
40 | */
41 | private String type;
42 |
43 | /**
44 | * 是否必须
45 | */
46 | private Boolean required;
47 |
48 | /**
49 | * 参数示例
50 | */
51 | private String example;
52 |
53 | /**
54 | * 参数描述
55 | */
56 | private String desc = "";
57 |
58 | /**
59 | * since
60 | */
61 | private String since;
62 |
63 | /**
64 | * version
65 | */
66 | private String version;
67 |
68 | /**
69 | * 子
70 | */
71 | private List childList = new ArrayList<>();
72 |
73 | /**
74 | * 是否是集合
75 | */
76 | private boolean isCollection = false;
77 |
78 | /**
79 | * 是否是 map
80 | */
81 | private boolean isMap = false;
82 | }
83 |
--------------------------------------------------------------------------------
/src/main/java/com/liuzhihang/doc/view/action/toolbar/window/catalog/CatalogClearAction.java:
--------------------------------------------------------------------------------
1 | package com.liuzhihang.doc.view.action.toolbar.window.catalog;
2 |
3 | import com.intellij.openapi.actionSystem.AnAction;
4 | import com.intellij.openapi.actionSystem.AnActionEvent;
5 | import com.intellij.openapi.actionSystem.PlatformDataKeys;
6 | import com.intellij.openapi.project.Project;
7 | import com.intellij.ui.treeStructure.SimpleNode;
8 | import com.intellij.ui.treeStructure.SimpleTree;
9 | import com.liuzhihang.doc.view.data.DocViewDataKeys;
10 | import com.liuzhihang.doc.view.ui.window.DocViewNode;
11 | import com.liuzhihang.doc.view.utils.CustomFileUtils;
12 | import org.jetbrains.annotations.NotNull;
13 |
14 | /**
15 | * @author liuzhihang
16 | * @date 2021/10/23 19:55
17 | */
18 | public class CatalogClearAction extends AnAction {
19 |
20 | @Override
21 | public void actionPerformed(@NotNull AnActionEvent e) {
22 |
23 | // 获取当前project对象
24 | Project project = e.getData(PlatformDataKeys.PROJECT);
25 | SimpleTree simpleTree = e.getData(DocViewDataKeys.WINDOW_CATALOG_TREE);
26 |
27 | if (simpleTree == null || project == null) {
28 | return;
29 | }
30 |
31 | SimpleNode selectedNode = simpleTree.getSelectedNode();
32 |
33 | if (selectedNode instanceof DocViewNode) {
34 | DocViewNode docViewNode = (DocViewNode) selectedNode;
35 | CustomFileUtils.delete(project, docViewNode.docPath(project));
36 |
37 | }
38 |
39 | }
40 |
41 | }
42 |
--------------------------------------------------------------------------------
/src/main/java/com/liuzhihang/doc/view/action/toolbar/preview/MenuExportAllAction.java:
--------------------------------------------------------------------------------
1 | package com.liuzhihang.doc.view.action.toolbar.preview;
2 |
3 | import com.intellij.openapi.actionSystem.AnAction;
4 | import com.intellij.openapi.actionSystem.AnActionEvent;
5 | import com.intellij.openapi.actionSystem.PlatformDataKeys;
6 | import com.intellij.openapi.project.Project;
7 | import com.intellij.openapi.ui.popup.JBPopup;
8 | import com.liuzhihang.doc.view.data.DocViewDataKeys;
9 | import com.liuzhihang.doc.view.dto.DocView;
10 | import com.liuzhihang.doc.view.utils.ExportUtils;
11 | import org.jetbrains.annotations.NotNull;
12 |
13 | import java.util.List;
14 |
15 | /**
16 | * Preview 导出全部
17 | *
18 | * @author liuzhihang
19 | * @date 2021/10/23 22:31
20 | */
21 | public class MenuExportAllAction extends AnAction {
22 | @Override
23 | public void actionPerformed(@NotNull AnActionEvent e) {
24 |
25 | // 获取当前project对象
26 | Project project = e.getData(PlatformDataKeys.PROJECT);
27 | JBPopup popup = e.getData(DocViewDataKeys.PREVIEW_POPUP);
28 | DocView currentDocView = e.getData(DocViewDataKeys.PREVIEW_CURRENT_DOC_VIEW);
29 | List docViewList = e.getData(DocViewDataKeys.PREVIEW_DOC_VIEW_LIST);
30 |
31 | if (popup == null || project == null || currentDocView == null || docViewList == null) {
32 | return;
33 | }
34 |
35 | popup.cancel();
36 | ExportUtils.batchExportMarkdown(project, currentDocView.getPsiClass().getName(), docViewList);
37 |
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/src/main/java/com/liuzhihang/doc/view/integration/YuQueFacadeService.java:
--------------------------------------------------------------------------------
1 | package com.liuzhihang.doc.view.integration;
2 |
3 | import com.liuzhihang.doc.view.integration.dto.YuQueCreate;
4 | import com.liuzhihang.doc.view.integration.dto.YuQueResponse;
5 | import com.liuzhihang.doc.view.integration.dto.YuQueUpdate;
6 |
7 | /**
8 | * 语雀包装 service
9 | *
10 | * https://www.yuque.com/yuque/developer/doc#Response-1
11 | *
12 | * @author liuzhihang
13 | * @date 2022-03-31 23:01:56
14 | */
15 | public interface YuQueFacadeService {
16 |
17 | /**
18 | * 获取单篇文章
19 | *
20 | * @param url
21 | * @param token
22 | * @param namespace
23 | * @param slug
24 | * @return
25 | * @throws Exception
26 | */
27 | YuQueResponse getDoc(String url, String token, String namespace, String slug) throws Exception;
28 |
29 | /**
30 | * 创建文档
31 | *
32 | * @param url
33 | * @param token
34 | * @param namespace
35 | * @param yuQueCreate
36 | * @return
37 | * @throws Exception
38 | */
39 | YuQueResponse create(String url, String token, String namespace, YuQueCreate yuQueCreate) throws Exception;
40 |
41 | /**
42 | * 更新文档
43 | *
44 | * @param url
45 | * @param token
46 | * @param namespace
47 | * @param id 文章的 id
48 | * @param yuQueUpdate
49 | * @return
50 | * @throws Exception
51 | */
52 | YuQueResponse update(String url, String token, String namespace, Long id, YuQueUpdate yuQueUpdate) throws Exception;
53 | }
54 |
--------------------------------------------------------------------------------
/src/main/java/com/liuzhihang/doc/view/config/YuQueSettings.java:
--------------------------------------------------------------------------------
1 | package com.liuzhihang.doc.view.config;
2 |
3 | import com.intellij.openapi.components.PersistentStateComponent;
4 | import com.intellij.openapi.components.State;
5 | import com.intellij.openapi.components.Storage;
6 | import com.intellij.openapi.project.Project;
7 | import com.intellij.util.xmlb.XmlSerializerUtil;
8 | import lombok.Data;
9 | import org.jetbrains.annotations.NotNull;
10 | import org.jetbrains.annotations.Nullable;
11 |
12 | /**
13 | * ShowDoc 的相关设置
14 | *
15 | * @author liuzhihang
16 | * @date 2020/11/22 13:51
17 | */
18 | @Data
19 | @State(name = "DocViewYuQueSettingsComment", storages = {@Storage("DocViewYuQueSettings.xml")})
20 | public class YuQueSettings implements PersistentStateComponent {
21 |
22 | private String url = "https://www.yuque.com";
23 | private String apiUrl = "https://www.yuque.com/api/v2";
24 |
25 | private String token;
26 |
27 | private String login;
28 |
29 | private String repos;
30 |
31 |
32 | public static YuQueSettings getInstance(@NotNull Project project) {
33 | return project.getService(YuQueSettings.class);
34 | }
35 |
36 | @Override
37 | public @Nullable
38 | YuQueSettings getState() {
39 | return this;
40 | }
41 |
42 | @Override
43 | public void loadState(@NotNull YuQueSettings state) {
44 |
45 | XmlSerializerUtil.copyBean(state, this);
46 | }
47 |
48 | public String getNamespace() {
49 | return login + "/" + repos;
50 | }
51 |
52 | }
53 |
--------------------------------------------------------------------------------
/src/main/java/com/liuzhihang/doc/view/config/WindowSettings.java:
--------------------------------------------------------------------------------
1 | package com.liuzhihang.doc.view.config;
2 |
3 | import com.intellij.openapi.components.PersistentStateComponent;
4 | import com.intellij.openapi.components.State;
5 | import com.intellij.openapi.components.Storage;
6 | import com.intellij.openapi.project.Project;
7 | import com.intellij.util.xmlb.XmlSerializerUtil;
8 | import lombok.Data;
9 | import org.jetbrains.annotations.NotNull;
10 | import org.jetbrains.annotations.Nullable;
11 |
12 | /**
13 | * 配置持久保存
14 | *
15 | *
16 | * See IntelliJ Platform SDK DevGuide
17 | *
18 | * @author liuzhihang
19 | * @date 2020/2/27 19:02
20 | */
21 | @Data
22 | @State(name = "DocViewWindowSettingsComponent", storages = {@Storage("DocViewWindowSettings.xml")})
23 | public class WindowSettings implements PersistentStateComponent {
24 |
25 | /**
26 | * 范围
27 | */
28 | private String scope;
29 |
30 | /**
31 | * 包含接口
32 | */
33 | private boolean includeInterface = false;
34 |
35 |
36 | public static WindowSettings getInstance(@NotNull Project project) {
37 | return project.getService(WindowSettings.class);
38 | }
39 |
40 |
41 | @Nullable
42 | @Override
43 | public WindowSettings getState() {
44 | return this;
45 | }
46 |
47 | @Override
48 | public void loadState(@NotNull WindowSettings state) {
49 | XmlSerializerUtil.copyBean(state, this);
50 | }
51 |
52 |
53 | }
54 |
--------------------------------------------------------------------------------
/src/main/java/com/liuzhihang/doc/view/constant/FieldTypeConstant.java:
--------------------------------------------------------------------------------
1 | package com.liuzhihang.doc.view.constant;
2 |
3 | import com.google.common.collect.Sets;
4 | import org.jetbrains.annotations.NonNls;
5 |
6 | import java.util.HashMap;
7 | import java.util.Map;
8 | import java.util.Set;
9 |
10 | /**
11 | * @author liuzhihang
12 | * @date 2020/3/4 20:35
13 | */
14 | public final class FieldTypeConstant {
15 |
16 | private FieldTypeConstant() {
17 | }
18 |
19 | @NonNls
20 | public static final Map FIELD_TYPE = new HashMap<>(64);
21 |
22 | public static final Set BASE_TYPE_SET = Sets.newHashSet("byte", "short", "int", "long", "char", "float",
23 | "double", "boolean");
24 |
25 | /**
26 | * 包装类型 & String
27 | */
28 | public static final Set PACKAGE_TYPE_SET = Sets.newHashSet("Byte", "Short", "Integer", "Long", "Float", "Double",
29 | "Boolean", "String");
30 |
31 | static {
32 | // 包装数据类型
33 | FIELD_TYPE.put("Byte", 0);
34 | FIELD_TYPE.put("Short", 0);
35 | FIELD_TYPE.put("Integer", 0);
36 | FIELD_TYPE.put("Long", 0L);
37 | FIELD_TYPE.put("Float", 0.0F);
38 | FIELD_TYPE.put("Double", 0.0D);
39 | FIELD_TYPE.put("Boolean", false);
40 | // 其他
41 | FIELD_TYPE.put("String", "");
42 | FIELD_TYPE.put("BigDecimal", null);
43 | FIELD_TYPE.put("Date", null);
44 | FIELD_TYPE.put("LocalDate", null);
45 | FIELD_TYPE.put("LocalTime", null);
46 | FIELD_TYPE.put("LocalDateTime", null);
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/src/main/java/com/liuzhihang/doc/view/action/toolbar/window/WindowRefreshAction.java:
--------------------------------------------------------------------------------
1 | package com.liuzhihang.doc.view.action.toolbar.window;
2 |
3 | import com.intellij.openapi.actionSystem.AnAction;
4 | import com.intellij.openapi.actionSystem.AnActionEvent;
5 | import com.intellij.openapi.actionSystem.PlatformDataKeys;
6 | import com.intellij.openapi.progress.ProgressIndicator;
7 | import com.intellij.openapi.progress.ProgressManager;
8 | import com.intellij.openapi.progress.Task;
9 | import com.intellij.openapi.project.Project;
10 | import com.liuzhihang.doc.view.data.DocViewDataKeys;
11 | import com.liuzhihang.doc.view.ui.window.DocViewWindowPanel;
12 | import org.jetbrains.annotations.NotNull;
13 |
14 | /**
15 | * @author liuzhihang
16 | * @date 2021/10/23 19:55
17 | */
18 | public class WindowRefreshAction extends AnAction {
19 |
20 | @Override
21 | public void actionPerformed(@NotNull AnActionEvent e) {
22 |
23 | // 获取当前project对象
24 | Project project = e.getData(PlatformDataKeys.PROJECT);
25 | DocViewWindowPanel docViewWindowPanel = e.getData(DocViewDataKeys.WINDOW_PANE);
26 |
27 | if (docViewWindowPanel == null || project == null) {
28 | return;
29 | }
30 |
31 | ProgressManager.getInstance().run(new Task.Backgroundable(project, "Doc View", false) {
32 | @Override
33 | public void run(@NotNull ProgressIndicator progressIndicator) {
34 |
35 | progressIndicator.setText("Directory refreshing");
36 | docViewWindowPanel.updateCatalogTree();
37 | }
38 | });
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/src/test/http/YApiGetTest.http:
--------------------------------------------------------------------------------
1 | ###
2 | POST http://apidoc.xxx.com:3000/api/interface/save
3 | Content-Type: application/json
4 |
5 | {
6 | "yapiUrl": "http://apidoc.opaydev.com:3000",
7 | "token": "33622ea7067e12c0d632e1362a2eec5964175bc3bd601bb12d5696e8ee38126c",
8 | "projectId": 116,
9 | "id": null,
10 | "catid": 1649,
11 | "path": "/user/requestParamUserAc11",
12 | "method": "GET",
13 | "req_body_type": "form",
14 | "req_body_other": null,
15 | "req_body_is_json_schema": true,
16 | "req_body_form": [
17 | {
18 | "name": "userId",
19 | "type": "String",
20 | "example": null,
21 | "desc": "",
22 | "required": "0"
23 | }
24 | ],
25 | "req_params": [],
26 | "req_headers": [
27 | {
28 | "name": "Content-Type",
29 | "example": null,
30 | "desc": "application/x-www-form-urlencoded",
31 | "value": "application/x-www-form-urlencoded",
32 | "required": "1"
33 | }
34 | ],
35 | "req_query": [],
36 | "res_body_type": "json",
37 | "res_body": "{\"description\":\" \",\"type\":\"object\",\"title\":\" \",\"required\":[],\"properties\":{\"code\":{\"type\":{},\"description\":\"响应码\"},\"msg\":{\"type\":{},\"description\":\"响应信息\"},\"data\":{\"type\":{},\"description\":\"响应数据\"}}}",
38 | "desc": "",
39 | "title": "requestParamUser111",
40 | "switch_notice": false,
41 | "status": "undone",
42 | "res_body_is_json_schema": true,
43 | "markdown": "**接口名称:**\n\nrequestParamUser111\n\n**接口描述:**\n\n\n\n**请求示例:**\n\nnull\n\n**返回示例:**\n\n{\n \"code\": \"\",\n \"msg\": \"\",\n \"data\": {\n \"userId\": \"\"\n }\n}"
44 | }
--------------------------------------------------------------------------------
/src/main/java/com/liuzhihang/doc/view/action/toolbar/window/catalog/CatalogOpenAction.java:
--------------------------------------------------------------------------------
1 | package com.liuzhihang.doc.view.action.toolbar.window.catalog;
2 |
3 | import com.intellij.openapi.actionSystem.AnAction;
4 | import com.intellij.openapi.actionSystem.AnActionEvent;
5 | import com.intellij.openapi.actionSystem.PlatformDataKeys;
6 | import com.intellij.openapi.project.Project;
7 | import com.intellij.ui.TreeExpandCollapse;
8 | import com.intellij.ui.treeStructure.SimpleNode;
9 | import com.intellij.ui.treeStructure.SimpleTree;
10 | import com.liuzhihang.doc.view.data.DocViewDataKeys;
11 | import com.liuzhihang.doc.view.ui.window.MethodNode;
12 | import com.liuzhihang.doc.view.utils.CustomFileUtils;
13 | import org.jetbrains.annotations.NotNull;
14 |
15 | /**
16 | * @author liuzhihang
17 | * @date 2021/10/23 19:55
18 | */
19 | public class CatalogOpenAction extends AnAction {
20 |
21 | @Override
22 | public void actionPerformed(@NotNull AnActionEvent e) {
23 |
24 | // 获取当前project对象
25 | Project project = e.getData(PlatformDataKeys.PROJECT);
26 | SimpleTree simpleTree = e.getData(DocViewDataKeys.WINDOW_CATALOG_TREE);
27 |
28 | if (simpleTree == null || project == null) {
29 | return;
30 | }
31 |
32 | SimpleNode selectedNode = simpleTree.getSelectedNode();
33 |
34 | if (selectedNode instanceof MethodNode) {
35 | MethodNode methodNode = (MethodNode) selectedNode;
36 | CustomFileUtils.openMd(project, methodNode);
37 | } else {
38 | TreeExpandCollapse.expandAll(simpleTree);
39 | }
40 |
41 | }
42 |
43 | }
44 |
--------------------------------------------------------------------------------
/src/main/java/com/liuzhihang/doc/view/integration/impl/ShowDocFacadeServiceImpl.java:
--------------------------------------------------------------------------------
1 | package com.liuzhihang.doc.view.integration.impl;
2 |
3 | import com.google.gson.Gson;
4 | import com.google.gson.GsonBuilder;
5 | import com.google.gson.JsonObject;
6 | import com.intellij.openapi.diagnostic.Logger;
7 | import com.liuzhihang.doc.view.integration.ShowDocFacadeService;
8 | import com.liuzhihang.doc.view.integration.dto.ShowDocUpdateRequest;
9 | import com.liuzhihang.doc.view.integration.dto.ShowDocUpdateResponse;
10 | import com.liuzhihang.doc.view.utils.HttpUtils;
11 | import org.apache.commons.lang3.StringUtils;
12 |
13 | /**
14 | * @author liuzhihang
15 | * @date 2021/7/27 11:53
16 | */
17 | public class ShowDocFacadeServiceImpl implements ShowDocFacadeService {
18 |
19 | private static final Logger LOGGER = Logger.getInstance(ShowDocFacadeServiceImpl.class);
20 |
21 | private static final Gson gson = new GsonBuilder().serializeNulls().create();
22 |
23 | @Override
24 | public ShowDocUpdateResponse updateByApi(ShowDocUpdateRequest request) throws Exception {
25 |
26 | String resp = HttpUtils.post(request.getShowDocUrl() + "/api/item/updateByApi", gson.toJson(request));
27 |
28 | if (StringUtils.isBlank(resp)) {
29 | throw new Exception("ShowDoc 接口返回为空");
30 | }
31 |
32 | JsonObject jsonObject = gson.fromJson(resp, JsonObject.class);
33 |
34 | if (!jsonObject.get("error_code").getAsString().equals("0")) {
35 | throw new Exception("ShowDoc 接口返回失败:" + resp);
36 | }
37 | return gson.fromJson(jsonObject, ShowDocUpdateResponse.class);
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/src/main/java/com/liuzhihang/doc/view/action/toolbar/window/catalog/CatalogHttpClientAction.java:
--------------------------------------------------------------------------------
1 | package com.liuzhihang.doc.view.action.toolbar.window.catalog;
2 |
3 | import com.intellij.openapi.actionSystem.AnAction;
4 | import com.intellij.openapi.actionSystem.AnActionEvent;
5 | import com.intellij.openapi.actionSystem.PlatformDataKeys;
6 | import com.intellij.openapi.project.Project;
7 | import com.intellij.ui.TreeExpandCollapse;
8 | import com.intellij.ui.treeStructure.SimpleNode;
9 | import com.intellij.ui.treeStructure.SimpleTree;
10 | import com.liuzhihang.doc.view.data.DocViewDataKeys;
11 | import com.liuzhihang.doc.view.ui.window.MethodNode;
12 | import com.liuzhihang.doc.view.utils.CustomFileUtils;
13 |
14 | /**
15 | * window 窗口目录树, 右键生成 HttpClient 功能
16 | *
17 | * @author liuzhihang
18 | * @version CatalogHttpClientAction.java, v 0.1 2022/6/16 17:53 liuzhihang
19 | */
20 | public class CatalogHttpClientAction extends AnAction {
21 |
22 | @Override
23 | public void actionPerformed(AnActionEvent e) {
24 |
25 | // 获取当前project对象
26 | Project project = e.getData(PlatformDataKeys.PROJECT);
27 | SimpleTree simpleTree = e.getData(DocViewDataKeys.WINDOW_CATALOG_TREE);
28 |
29 | if (simpleTree == null || project == null) {
30 | return;
31 | }
32 |
33 | SimpleNode selectedNode = simpleTree.getSelectedNode();
34 |
35 | if (selectedNode instanceof MethodNode) {
36 | MethodNode methodNode = (MethodNode) selectedNode;
37 | CustomFileUtils.openHttp(project, methodNode);
38 | } else {
39 | TreeExpandCollapse.expandAll(simpleTree);
40 | }
41 |
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/src/main/resources/icons/clear.svg:
--------------------------------------------------------------------------------
1 |
3 |
--------------------------------------------------------------------------------
/src/main/java/com/liuzhihang/doc/view/action/toolbar/window/catalog/CatalogExportAction.java:
--------------------------------------------------------------------------------
1 | package com.liuzhihang.doc.view.action.toolbar.window.catalog;
2 |
3 | import com.intellij.openapi.actionSystem.AnAction;
4 | import com.intellij.openapi.actionSystem.AnActionEvent;
5 | import com.intellij.openapi.actionSystem.PlatformDataKeys;
6 | import com.intellij.openapi.project.Project;
7 | import com.intellij.ui.treeStructure.SimpleNode;
8 | import com.intellij.ui.treeStructure.SimpleTree;
9 | import com.liuzhihang.doc.view.data.DocViewDataKeys;
10 | import com.liuzhihang.doc.view.dto.DocView;
11 | import com.liuzhihang.doc.view.ui.window.DocViewNode;
12 | import com.liuzhihang.doc.view.utils.ExportUtils;
13 | import org.jetbrains.annotations.NotNull;
14 |
15 | import java.util.List;
16 |
17 | /**
18 | * @author liuzhihang
19 | * @date 2021/10/23 19:55
20 | */
21 | public class CatalogExportAction extends AnAction {
22 |
23 | @Override
24 | public void actionPerformed(@NotNull AnActionEvent e) {
25 |
26 | // 获取当前project对象
27 | Project project = e.getData(PlatformDataKeys.PROJECT);
28 | SimpleTree simpleTree = e.getData(DocViewDataKeys.WINDOW_CATALOG_TREE);
29 |
30 | if (simpleTree == null || project == null) {
31 | return;
32 | }
33 |
34 | SimpleNode selectedNode = simpleTree.getSelectedNode();
35 |
36 | if (selectedNode instanceof DocViewNode) {
37 | DocViewNode docViewNode = (DocViewNode) selectedNode;
38 | List docViews = docViewNode.docViewList();
39 | ExportUtils.batchExportMarkdown(project, docViewNode.getName(), docViews);
40 | }
41 |
42 | }
43 |
44 |
45 | }
46 |
--------------------------------------------------------------------------------
/src/main/resources/icons/clear_dark.svg:
--------------------------------------------------------------------------------
1 |
3 |
--------------------------------------------------------------------------------
/src/main/java/com/liuzhihang/doc/view/config/SettingsConfigurable.java:
--------------------------------------------------------------------------------
1 | package com.liuzhihang.doc.view.config;
2 |
3 | import com.intellij.openapi.options.ConfigurationException;
4 | import com.intellij.openapi.options.SearchableConfigurable;
5 | import com.intellij.openapi.project.Project;
6 | import com.liuzhihang.doc.view.ui.SettingsForm;
7 | import org.jetbrains.annotations.Nls;
8 | import org.jetbrains.annotations.NotNull;
9 | import org.jetbrains.annotations.Nullable;
10 |
11 | import javax.swing.*;
12 |
13 | /**
14 | * @author liuzhihang
15 | * @date 2020/3/4 13:05
16 | */
17 | public class SettingsConfigurable implements SearchableConfigurable {
18 |
19 |
20 | private final Project project;
21 |
22 | private SettingsForm settingsForm;
23 |
24 | public SettingsConfigurable(@NotNull Project project) {
25 | this.project = project;
26 | }
27 |
28 | @NotNull
29 | @Override
30 | public String getId() {
31 | return "liuzhihang.api.doc.SettingsConfigurable";
32 | }
33 |
34 | @Nls(capitalization = Nls.Capitalization.Title)
35 | @Override
36 | public String getDisplayName() {
37 | return "Doc View";
38 | }
39 |
40 | @Nullable
41 | @Override
42 | public JComponent createComponent() {
43 |
44 | settingsForm = new SettingsForm(project);
45 |
46 | return settingsForm.getRootPanel();
47 | }
48 |
49 | @Override
50 | public boolean isModified() {
51 | return settingsForm.isModified();
52 | }
53 |
54 | @Override
55 | public void apply() throws ConfigurationException {
56 | settingsForm.apply();
57 | }
58 |
59 | @Override
60 | public void reset() {
61 | settingsForm.reset();
62 | }
63 |
64 | }
65 |
--------------------------------------------------------------------------------
/src/main/java/com/liuzhihang/doc/view/utils/VelocityUtils.java:
--------------------------------------------------------------------------------
1 | package com.liuzhihang.doc.view.utils;
2 |
3 | import com.liuzhihang.doc.view.dto.DocViewData;
4 | import org.apache.velocity.VelocityContext;
5 | import org.apache.velocity.app.VelocityEngine;
6 | import org.apache.velocity.runtime.RuntimeConstants;
7 |
8 | import java.io.StringWriter;
9 | import java.util.Properties;
10 |
11 | /**
12 | * 根据模版生成对应的内容
13 | *
14 | * @author liuzhihang
15 | * @date 2020/11/21 15:38
16 | */
17 | public class VelocityUtils {
18 |
19 | private static VelocityEngine engine;
20 | private static String VM_LOG_TAG = "DocView VelocityUtils";
21 |
22 | static {
23 | engine = new VelocityEngine();
24 | engine.setProperty(RuntimeConstants.PARSER_POOL_SIZE, 20);
25 | engine.setProperty(RuntimeConstants.INPUT_ENCODING, "UTF-8");
26 | // engine.setProperty(RuntimeConstants.OUTPUT_ENCODING, "UTF-8");
27 |
28 | Properties props = new Properties();
29 | props.put("runtime.log.logsystem.class", "org.apache.velocity.runtime.log.SimpleLog4JLogSystem");
30 | props.put("runtime.log.logsystem.log4j.category", "velocity");
31 | props.put("runtime.log.logsystem.log4j.logger", "velocity");
32 | engine.init(props);
33 | }
34 |
35 | public static String convert(String template, DocViewData data) {
36 |
37 |
38 | StringWriter writer = new StringWriter();
39 | VelocityContext velocityContext = new VelocityContext();
40 | velocityContext.put("DocView", data);
41 | boolean isSuccess = engine.evaluate(velocityContext, writer, VM_LOG_TAG, template);
42 | if (!isSuccess) {
43 | return "ERROR";
44 | }
45 |
46 |
47 | return writer.toString();
48 | }
49 |
50 | }
51 |
--------------------------------------------------------------------------------
/src/main/java/com/liuzhihang/doc/view/data/DocViewDataKeys.java:
--------------------------------------------------------------------------------
1 | package com.liuzhihang.doc.view.data;
2 |
3 | import com.intellij.openapi.actionSystem.DataKey;
4 | import com.intellij.openapi.ui.popup.JBPopup;
5 | import com.intellij.ui.treeStructure.SimpleTree;
6 | import com.liuzhihang.doc.view.dto.DocView;
7 | import com.liuzhihang.doc.view.ui.PreviewForm;
8 | import com.liuzhihang.doc.view.ui.window.DocViewWindowPanel;
9 | import com.liuzhihang.doc.view.ui.window.RootNode;
10 |
11 | import javax.swing.*;
12 | import java.util.List;
13 |
14 | /**
15 | * @author liuzhihang
16 | * @date 2021/10/23 21:04
17 | */
18 | public class DocViewDataKeys {
19 |
20 | /**
21 | * 目录树
22 | */
23 | public static final DataKey WINDOW_PANE = DataKey.create("DocViewWindowPane");
24 | public static final DataKey WINDOW_ROOT_NODE = DataKey.create("DocViewWindowRootNode");
25 | public static final DataKey WINDOW_CATALOG_TREE = DataKey.create("DocViewWindowTree");
26 | public static final DataKey WINDOW_TOOLBAR = DataKey.create("DocViewWindowToolbar");
27 |
28 |
29 | /**
30 | * Preview 界面
31 | */
32 | public static final DataKey PREVIEW_FORM = DataKey.create("PreviewForm");
33 | public static final DataKey PREVIEW_POPUP = DataKey.create("PreviewPop");
34 | public static final DataKey PREVIEW_CURRENT_DOC_VIEW = DataKey.create("PreviewCurrentDocView");
35 | public static final DataKey PREVIEW_MARKDOWN_TEXT = DataKey.create("PreviewMarkdownText");
36 | public static final DataKey> PREVIEW_DOC_VIEW_LIST = DataKey.create("PreviewDocViewList");
37 | public static final DataKey PREVIEW_TOOLBAR_PANEL = DataKey.create("PreviewToolbarPanel");
38 | }
39 |
--------------------------------------------------------------------------------
/src/main/java/com/liuzhihang/doc/view/notification/DocViewStartupNotification.java:
--------------------------------------------------------------------------------
1 | package com.liuzhihang.doc.view.notification;
2 |
3 | import com.intellij.ide.plugins.IdeaPluginDescriptor;
4 | import com.intellij.ide.plugins.PluginManagerCore;
5 | import com.intellij.openapi.application.ApplicationManager;
6 | import com.intellij.openapi.extensions.PluginId;
7 | import com.intellij.openapi.project.DumbAware;
8 | import com.intellij.openapi.project.Project;
9 | import com.intellij.openapi.startup.StartupActivity;
10 | import com.intellij.util.text.VersionComparatorUtil;
11 | import com.liuzhihang.doc.view.config.ApplicationSettings;
12 | import org.jetbrains.annotations.NotNull;
13 |
14 | /**
15 | * 安装新版本或者更新时提示
16 | *
17 | * @author liuzhihang
18 | * @date 2021/10/22 14:09
19 | */
20 | public class DocViewStartupNotification implements StartupActivity, DumbAware {
21 |
22 | @Override
23 | public void runActivity(@NotNull Project project) {
24 |
25 | if (ApplicationManager.getApplication().isUnitTestMode()) {
26 | return;
27 | }
28 | ApplicationSettings applicationSettings = ApplicationManager.getApplication().getService(ApplicationSettings.class);
29 |
30 | // 上次安装的版本
31 | String lastVersion = applicationSettings.getPluginVersion();
32 |
33 | IdeaPluginDescriptor plugin = PluginManagerCore.getPlugin(PluginId.getId("com.liuzhihang.doc-view"));
34 |
35 | // 一个版本只通知一次
36 | if (lastVersion != null && plugin != null) {
37 | final int compare = VersionComparatorUtil.compare(lastVersion, plugin.getVersion());
38 | if (compare < 0) {
39 | DocViewNotification.startupNotification(project);
40 | applicationSettings.setPluginVersion(plugin.getVersion());
41 | }
42 | }
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/src/main/java/com/liuzhihang/doc/view/config/YApiSettingsConfigurable.java:
--------------------------------------------------------------------------------
1 | package com.liuzhihang.doc.view.config;
2 |
3 | import com.intellij.openapi.options.ConfigurationException;
4 | import com.intellij.openapi.options.SearchableConfigurable;
5 | import com.intellij.openapi.project.Project;
6 | import com.liuzhihang.doc.view.ui.YApiSettingForm;
7 | import org.jetbrains.annotations.Nls;
8 | import org.jetbrains.annotations.NotNull;
9 | import org.jetbrains.annotations.Nullable;
10 |
11 | import javax.swing.*;
12 |
13 | /**
14 | * YApi 配置
15 | *
16 | * @author liuzhihang
17 | * @date 2021/6/8 17:10
18 | */
19 | public class YApiSettingsConfigurable implements SearchableConfigurable {
20 |
21 | private YApiSettingForm yApiSettingForm;
22 |
23 | private final Project project;
24 |
25 | public YApiSettingsConfigurable(@NotNull Project project) {
26 | this.project = project;
27 | }
28 |
29 | @NotNull
30 | @Override
31 | public String getId() {
32 | return "liuzhihang.api.doc.YApiSettingsConfigurable";
33 | }
34 |
35 | @Nls(capitalization = Nls.Capitalization.Title)
36 | @Override
37 | public String getDisplayName() {
38 | return "YApi Settings";
39 | }
40 |
41 | @Nullable
42 | @Override
43 | public JComponent createComponent() {
44 |
45 | yApiSettingForm = new YApiSettingForm(project);
46 |
47 | return yApiSettingForm.getRootPanel();
48 | }
49 |
50 |
51 | @Override
52 | public boolean isModified() {
53 |
54 | return yApiSettingForm.isModified();
55 | }
56 |
57 | @Override
58 | public void apply() throws ConfigurationException {
59 |
60 | yApiSettingForm.apply();
61 | }
62 |
63 | @Override
64 | public void reset() {
65 |
66 | yApiSettingForm.reset();
67 | }
68 |
69 |
70 | }
71 |
--------------------------------------------------------------------------------
/src/main/java/com/liuzhihang/doc/view/config/TemplateConfigurable.java:
--------------------------------------------------------------------------------
1 | package com.liuzhihang.doc.view.config;
2 |
3 | import com.intellij.openapi.options.ConfigurationException;
4 | import com.intellij.openapi.options.SearchableConfigurable;
5 | import com.intellij.openapi.project.Project;
6 | import com.liuzhihang.doc.view.ui.TemplateSettingForm;
7 | import org.jetbrains.annotations.Nls;
8 | import org.jetbrains.annotations.NotNull;
9 | import org.jetbrains.annotations.Nullable;
10 |
11 | import javax.swing.*;
12 |
13 | /**
14 | * 设置模版
15 | *
16 | * @author liuzhihang
17 | * @date 2020/3/4 13:05
18 | */
19 | public class TemplateConfigurable implements SearchableConfigurable {
20 |
21 | private TemplateSettingForm templateSettingForm;
22 |
23 | private final Project project;
24 |
25 | public TemplateConfigurable(@NotNull Project project) {
26 | this.project = project;
27 | }
28 |
29 |
30 | @NotNull
31 | @Override
32 | public String getId() {
33 | return "liuzhihang.api.doc.TemplateConfigurable";
34 | }
35 |
36 | @Nls(capitalization = Nls.Capitalization.Title)
37 | @Override
38 | public String getDisplayName() {
39 | return "Markdown Template";
40 | }
41 |
42 | @Nullable
43 | @Override
44 | public JComponent createComponent() {
45 |
46 | templateSettingForm = new TemplateSettingForm(project);
47 |
48 | return templateSettingForm.createCenterPanel();
49 | }
50 |
51 | @Override
52 | public boolean isModified() {
53 |
54 | return templateSettingForm.isModified();
55 | }
56 |
57 | @Override
58 | public void apply() throws ConfigurationException {
59 |
60 | templateSettingForm.apply();
61 | }
62 |
63 | @Override
64 | public void reset() {
65 |
66 | templateSettingForm.reset();
67 | }
68 | }
69 |
--------------------------------------------------------------------------------
/src/main/java/com/liuzhihang/doc/view/config/YuQueSettingsConfigurable.java:
--------------------------------------------------------------------------------
1 | package com.liuzhihang.doc.view.config;
2 |
3 | import com.intellij.openapi.options.ConfigurationException;
4 | import com.intellij.openapi.options.SearchableConfigurable;
5 | import com.intellij.openapi.project.Project;
6 | import com.liuzhihang.doc.view.ui.YuQueSettingForm;
7 | import org.jetbrains.annotations.Nls;
8 | import org.jetbrains.annotations.NotNull;
9 | import org.jetbrains.annotations.Nullable;
10 |
11 | import javax.swing.*;
12 |
13 | /**
14 | * YApi 配置
15 | *
16 | * @author liuzhihang
17 | * @date 2021/6/8 17:10
18 | */
19 | public class YuQueSettingsConfigurable implements SearchableConfigurable {
20 |
21 | private YuQueSettingForm yuQueSettingForm;
22 |
23 | private final Project project;
24 |
25 | public YuQueSettingsConfigurable(@NotNull Project project) {
26 | this.project = project;
27 | }
28 |
29 | @NotNull
30 | @Override
31 | public String getId() {
32 | return "liuzhihang.api.doc.YuQueSettingsConfigurable";
33 | }
34 |
35 | @Nls(capitalization = Nls.Capitalization.Title)
36 | @Override
37 | public String getDisplayName() {
38 | return "YuQue Settings";
39 | }
40 |
41 | @Nullable
42 | @Override
43 | public JComponent createComponent() {
44 |
45 | yuQueSettingForm = new YuQueSettingForm(project);
46 |
47 | return yuQueSettingForm.getRootPanel();
48 | }
49 |
50 |
51 | @Override
52 | public boolean isModified() {
53 |
54 | return yuQueSettingForm.isModified();
55 | }
56 |
57 | @Override
58 | public void apply() throws ConfigurationException {
59 |
60 | yuQueSettingForm.apply();
61 | }
62 |
63 | @Override
64 | public void reset() {
65 |
66 | yuQueSettingForm.reset();
67 | }
68 |
69 |
70 | }
71 |
--------------------------------------------------------------------------------
/src/main/java/com/liuzhihang/doc/view/config/ShowDocSettingsConfigurable.java:
--------------------------------------------------------------------------------
1 | package com.liuzhihang.doc.view.config;
2 |
3 | import com.intellij.openapi.options.ConfigurationException;
4 | import com.intellij.openapi.options.SearchableConfigurable;
5 | import com.intellij.openapi.project.Project;
6 | import com.liuzhihang.doc.view.ui.ShowDocSettingForm;
7 | import org.jetbrains.annotations.Nls;
8 | import org.jetbrains.annotations.NotNull;
9 | import org.jetbrains.annotations.Nullable;
10 |
11 | import javax.swing.*;
12 |
13 | /**
14 | * YApi 配置
15 | *
16 | * @author liuzhihang
17 | * @date 2021/6/8 17:10
18 | */
19 | public class ShowDocSettingsConfigurable implements SearchableConfigurable {
20 |
21 | private ShowDocSettingForm showDocSettingForm;
22 |
23 | private final Project project;
24 |
25 | public ShowDocSettingsConfigurable(@NotNull Project project) {
26 | this.project = project;
27 | }
28 |
29 | @NotNull
30 | @Override
31 | public String getId() {
32 | return "liuzhihang.api.doc.ShowDocSettingsConfigurable";
33 | }
34 |
35 | @Nls(capitalization = Nls.Capitalization.Title)
36 | @Override
37 | public String getDisplayName() {
38 | return "ShowDoc Settings";
39 | }
40 |
41 | @Nullable
42 | @Override
43 | public JComponent createComponent() {
44 |
45 | showDocSettingForm = new ShowDocSettingForm(project);
46 |
47 | return showDocSettingForm.getRootPanel();
48 | }
49 |
50 |
51 | @Override
52 | public boolean isModified() {
53 |
54 | return showDocSettingForm.isModified();
55 | }
56 |
57 | @Override
58 | public void apply() throws ConfigurationException {
59 |
60 | showDocSettingForm.apply();
61 | }
62 |
63 | @Override
64 | public void reset() {
65 |
66 | showDocSettingForm.reset();
67 | }
68 |
69 |
70 | }
71 |
--------------------------------------------------------------------------------
/src/main/java/com/liuzhihang/doc/view/config/TemplateSettings.java:
--------------------------------------------------------------------------------
1 | package com.liuzhihang.doc.view.config;
2 |
3 | import com.intellij.openapi.components.PersistentStateComponent;
4 | import com.intellij.openapi.components.State;
5 | import com.intellij.openapi.components.Storage;
6 | import com.intellij.openapi.project.Project;
7 | import com.intellij.util.xmlb.XmlSerializerUtil;
8 | import com.liuzhihang.doc.view.DocViewBundle;
9 | import org.jetbrains.annotations.NotNull;
10 | import org.jetbrains.annotations.Nullable;
11 |
12 | /**
13 | * DocView 模版设置
14 | *
15 | * @author liuzhihang
16 | * @date 2020/11/22 13:51
17 | */
18 | @State(name = "TemplateSettingsComponent", storages = {@Storage("DocViewTemplateSettings.xml")})
19 | public class TemplateSettings implements PersistentStateComponent {
20 |
21 | /**
22 | * spring 的模版
23 | */
24 | private String springTemplate = DocViewBundle.message("template.spring.init");
25 | private String dubboTemplate = DocViewBundle.message("template.dubbo.init");
26 |
27 | public static TemplateSettings getInstance(@NotNull Project project) {
28 | return project.getService(TemplateSettings.class);
29 | }
30 |
31 |
32 | @Nullable
33 | @Override
34 | public TemplateSettings getState() {
35 | return this;
36 | }
37 |
38 | @Override
39 | public void loadState(@NotNull TemplateSettings state) {
40 | XmlSerializerUtil.copyBean(state, this);
41 | }
42 |
43 |
44 | public String getSpringTemplate() {
45 | return springTemplate;
46 | }
47 |
48 | public void setSpringTemplate(String springTemplate) {
49 | this.springTemplate = springTemplate;
50 | }
51 |
52 | public String getDubboTemplate() {
53 | return dubboTemplate;
54 | }
55 |
56 | public void setDubboTemplate(String dubboTemplate) {
57 | this.dubboTemplate = dubboTemplate;
58 | }
59 | }
60 |
--------------------------------------------------------------------------------
/src/main/java/com/liuzhihang/doc/view/action/toolbar/preview/PreviewRightCopyAction.java:
--------------------------------------------------------------------------------
1 | package com.liuzhihang.doc.view.action.toolbar.preview;
2 |
3 | import com.intellij.openapi.actionSystem.AnAction;
4 | import com.intellij.openapi.actionSystem.AnActionEvent;
5 | import com.intellij.openapi.actionSystem.PlatformDataKeys;
6 | import com.intellij.openapi.project.Project;
7 | import com.intellij.openapi.ui.popup.JBPopup;
8 | import com.liuzhihang.doc.view.DocViewBundle;
9 | import com.liuzhihang.doc.view.data.DocViewDataKeys;
10 | import com.liuzhihang.doc.view.dto.DocView;
11 | import com.liuzhihang.doc.view.notification.DocViewNotification;
12 | import org.jetbrains.annotations.NotNull;
13 |
14 | import java.awt.*;
15 | import java.awt.datatransfer.Clipboard;
16 | import java.awt.datatransfer.StringSelection;
17 |
18 | /**
19 | * Preview 右侧复制
20 | *
21 | * @author liuzhihang
22 | * @date 2021/10/23 22:31
23 | */
24 | public class PreviewRightCopyAction extends AnAction {
25 | @Override
26 | public void actionPerformed(@NotNull AnActionEvent e) {
27 |
28 | // 获取当前project对象
29 | Project project = e.getData(PlatformDataKeys.PROJECT);
30 | JBPopup popup = e.getData(DocViewDataKeys.PREVIEW_POPUP);
31 | DocView currentDocView = e.getData(DocViewDataKeys.PREVIEW_CURRENT_DOC_VIEW);
32 | String currentMarkdownText = e.getData(DocViewDataKeys.PREVIEW_MARKDOWN_TEXT);
33 |
34 | if (popup == null || project == null || currentDocView == null || currentMarkdownText == null) {
35 | return;
36 | }
37 |
38 | StringSelection selection = new StringSelection(currentMarkdownText);
39 | Clipboard clipboard = Toolkit.getDefaultToolkit().getSystemClipboard();
40 | clipboard.setContents(selection, selection);
41 |
42 | DocViewNotification.notifyInfo(project, DocViewBundle.message("notify.copy.success", currentDocView.getName()));
43 |
44 | }
45 |
46 |
47 | }
48 |
--------------------------------------------------------------------------------
/src/main/java/com/liuzhihang/doc/view/ui/SupportForm.java:
--------------------------------------------------------------------------------
1 | package com.liuzhihang.doc.view.ui;
2 |
3 | import com.intellij.ide.BrowserUtil;
4 | import com.intellij.openapi.project.Project;
5 | import com.intellij.openapi.ui.DialogWrapper;
6 | import com.intellij.ui.components.labels.LinkLabel;
7 | import com.intellij.util.ui.JBUI;
8 | import com.liuzhihang.doc.view.DocViewBundle;
9 | import org.jetbrains.annotations.NotNull;
10 | import org.jetbrains.annotations.Nullable;
11 |
12 | import javax.swing.*;
13 |
14 | /**
15 | * @author liuzhihang
16 | * @date 2020/11/11 20:27
17 | */
18 | public class SupportForm extends DialogWrapper {
19 |
20 | private JPanel rootPanel;
21 | private LinkLabel starLinkLabel;
22 | private LinkLabel reportLinkLabel;
23 | private LinkLabel discussionsLinkLabel;
24 | private LinkLabel websiteLinkLabel;
25 |
26 | public SupportForm(@NotNull Project project) {
27 | super(project, true);
28 |
29 | init();
30 |
31 | starLinkLabel.setIcon(null);
32 | reportLinkLabel.setIcon(null);
33 | discussionsLinkLabel.setIcon(null);
34 | websiteLinkLabel.setIcon(null);
35 |
36 | rootPanel.setBorder(JBUI.Borders.empty(12, 15));
37 | rootPanel.setBackground(UIManager.getColor("TextArea.background"));
38 | starLinkLabel.setListener((source, data) -> BrowserUtil.browse(data), DocViewBundle.message("github"));
39 | reportLinkLabel.setListener((source, data) -> BrowserUtil.browse(data), DocViewBundle.message("issues"));
40 | discussionsLinkLabel.setListener((source, data) -> BrowserUtil.browse(data), DocViewBundle.message("discussions"));
41 | websiteLinkLabel.setListener((source, data) -> BrowserUtil.browse(data), DocViewBundle.message("website"));
42 |
43 | }
44 |
45 | @Nullable
46 | @Override
47 | public JComponent createCenterPanel() {
48 | return rootPanel;
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/src/main/java/com/liuzhihang/doc/view/utils/FeignPsiUtil.java:
--------------------------------------------------------------------------------
1 | package com.liuzhihang.doc.view.utils;
2 |
3 | import com.intellij.codeInsight.AnnotationUtil;
4 | import com.intellij.openapi.module.Module;
5 | import com.intellij.psi.PsiAnnotation;
6 | import com.intellij.psi.PsiClass;
7 | import com.intellij.psi.PsiElement;
8 | import com.intellij.psi.PsiModifierList;
9 | import com.intellij.psi.impl.java.stubs.index.JavaAnnotationIndex;
10 | import com.intellij.psi.search.GlobalSearchScope;
11 | import com.liuzhihang.doc.view.constant.SpringConstant;
12 | import org.jetbrains.annotations.NotNull;
13 |
14 | import java.util.Collection;
15 | import java.util.LinkedList;
16 | import java.util.List;
17 |
18 | /**
19 | * @author liuzhihang
20 | * @date 2021/10/23 17:38
21 | */
22 | public class FeignPsiUtil {
23 |
24 | /**
25 | * 检查类或者接口是否是 Feign 接口
26 | *
27 | * @param psiClass
28 | * @return
29 | */
30 | public static boolean isFeignClass(@NotNull PsiClass psiClass) {
31 |
32 | // 必须匹配是 Feign 注解才可以
33 | return psiClass.isInterface() && AnnotationUtil.isAnnotated(psiClass, SpringConstant.FEIGN_CLIENT, 0);
34 | }
35 |
36 | public static List findDocViewFromModule(Module module) {
37 |
38 | Collection psiAnnotations = JavaAnnotationIndex.getInstance().get("FeignClient", module.getProject(), GlobalSearchScope.moduleScope(module));
39 |
40 | List psiClasses = new LinkedList<>();
41 |
42 | for (PsiAnnotation psiAnnotation : psiAnnotations) {
43 | PsiModifierList psiModifierList = (PsiModifierList) psiAnnotation.getParent();
44 | PsiElement psiElement = psiModifierList.getParent();
45 |
46 | if (psiElement instanceof PsiClass && isFeignClass((PsiClass) psiElement)) {
47 | psiClasses.add((PsiClass) psiElement);
48 | }
49 | }
50 | return psiClasses;
51 | }
52 |
53 | }
54 |
--------------------------------------------------------------------------------
/src/main/java/com/liuzhihang/doc/view/ui/ParamDocEditor.form:
--------------------------------------------------------------------------------
1 |
2 |
41 |
--------------------------------------------------------------------------------
/src/main/java/com/liuzhihang/doc/view/ui/window/RootNode.java:
--------------------------------------------------------------------------------
1 | package com.liuzhihang.doc.view.ui.window;
2 |
3 | import com.intellij.icons.AllIcons;
4 | import com.intellij.openapi.module.Module;
5 | import com.intellij.openapi.module.ModuleManager;
6 | import com.intellij.openapi.project.Project;
7 | import com.intellij.ui.treeStructure.SimpleNode;
8 | import com.liuzhihang.doc.view.dto.DocView;
9 |
10 | import java.util.ArrayList;
11 | import java.util.Collection;
12 | import java.util.List;
13 | import java.util.stream.Collectors;
14 |
15 | /**
16 | * 根目录
17 | *
18 | * @author liuzhihang
19 | * @date 2022/4/4 16:56
20 | */
21 | public class RootNode extends DocViewNode {
22 |
23 | private final List moduleNodes = new ArrayList<>();
24 |
25 | public RootNode() {
26 | super(null);
27 | getTemplatePresentation().setIcon(AllIcons.Nodes.ModuleGroup);
28 | getTemplatePresentation().setPresentableText(getName());
29 | }
30 |
31 | @Override
32 | public void updateNode(Project project) {
33 | cleanUpCache();
34 | moduleNodes.clear();
35 |
36 | Module[] modules = ModuleManager.getInstance(project).getModules();
37 | for (Module module : modules) {
38 | ModuleNode moduleNode = new ModuleNode(this, module);
39 | if (moduleNode.getChildCount() > 0) {
40 | moduleNodes.add(moduleNode);
41 | }
42 | }
43 | update();
44 | }
45 |
46 | @Override
47 | public String docPath(Project project) {
48 | return "Doc View";
49 | }
50 |
51 | @Override
52 | public String httpPath(Project project) {
53 | return "Http";
54 | }
55 |
56 | @Override
57 | protected SimpleNode[] buildChildren() {
58 | return moduleNodes.toArray(new SimpleNode[0]);
59 | }
60 |
61 | @Override
62 | public String getName() {
63 | return "Doc View";
64 | }
65 |
66 | public List docViewList() {
67 |
68 | return moduleNodes.stream().map(ModuleNode::docViewList).flatMap(Collection::stream).collect(Collectors.toList());
69 | }
70 | }
71 |
--------------------------------------------------------------------------------
/src/main/java/com/liuzhihang/doc/view/ui/Preview.form:
--------------------------------------------------------------------------------
1 |
2 |
43 |
--------------------------------------------------------------------------------
/src/main/resources/icons/json.svg:
--------------------------------------------------------------------------------
1 |
2 |
8 |
--------------------------------------------------------------------------------
/src/main/resources/icons/json_dark.svg:
--------------------------------------------------------------------------------
1 |
2 |
8 |
--------------------------------------------------------------------------------
/src/main/java/com/liuzhihang/doc/view/ui/WindowFilterForm.java:
--------------------------------------------------------------------------------
1 | package com.liuzhihang.doc.view.ui;
2 |
3 | import com.intellij.openapi.module.Module;
4 | import com.intellij.openapi.module.ModuleManager;
5 | import com.intellij.openapi.project.Project;
6 | import com.intellij.ui.IdeBorderFactory;
7 | import com.intellij.util.ui.JBUI;
8 | import com.liuzhihang.doc.view.config.WindowSettings;
9 | import org.jetbrains.annotations.NotNull;
10 |
11 | import javax.swing.*;
12 | import javax.swing.border.TitledBorder;
13 |
14 | /**
15 | * @author liuzhihang
16 | * @date 2021/10/25 12:11
17 | */
18 | public class WindowFilterForm {
19 |
20 | private static final TitledBorder scope = IdeBorderFactory.createTitledBorder("读取范围");
21 | private static final TitledBorder otherSettings = IdeBorderFactory.createTitledBorder("其他设置");
22 |
23 | private final Project project;
24 | private final WindowSettings windowSettings;
25 |
26 | private JCheckBox interfaceCheckBox;
27 | private JComboBox scopeComboBox;
28 | private JPanel rootPane;
29 | private JPanel scopePanel;
30 | private JPanel otherSettingsPanel;
31 |
32 | public WindowFilterForm(@NotNull Project project) {
33 | this.project = project;
34 | this.windowSettings = WindowSettings.getInstance(project);
35 |
36 | initUI();
37 | initFilterPane();
38 | initFilterListener();
39 | }
40 |
41 | private void initUI() {
42 |
43 | scopePanel.setBorder(scope);
44 | otherSettingsPanel.setBorder(otherSettings);
45 | rootPane.setBorder(JBUI.Borders.empty(5));
46 |
47 |
48 | }
49 |
50 | private void initFilterPane() {
51 |
52 | interfaceCheckBox.setSelected(windowSettings.isIncludeInterface());
53 |
54 | Module[] modules = ModuleManager.getInstance(project).getModules();
55 |
56 | for (Module module : modules) {
57 | scopeComboBox.addItem(module.getName());
58 | }
59 |
60 | }
61 |
62 | private void initFilterListener() {
63 | interfaceCheckBox.addChangeListener(e -> windowSettings.setIncludeInterface(interfaceCheckBox.isSelected()));
64 | scopeComboBox.addItemListener(e -> windowSettings.setScope((String) scopeComboBox.getSelectedItem()));
65 | }
66 |
67 | }
68 |
--------------------------------------------------------------------------------
/src/main/java/icons/DocViewIcons.java:
--------------------------------------------------------------------------------
1 | package icons;
2 |
3 | import com.intellij.openapi.util.IconLoader;
4 |
5 | import javax.swing.*;
6 |
7 | /**
8 | * 图标管理: 图标地址
9 | *
10 | * @author liuzhihang
11 | * @date 2021/2/28 14:49
12 | */
13 | public interface DocViewIcons {
14 |
15 | /**
16 | * 插件图标:在侧栏树勇
17 | */
18 | Icon DOC_VIEW = IconLoader.getIcon("/icons/markdown.svg", DocViewIcons.class);
19 |
20 | /**
21 | * 清理缓存
22 | */
23 | Icon CLEAR = IconLoader.getIcon("/icons/clearCash.svg", DocViewIcons.class);
24 |
25 | /**
26 | * 上传
27 | */
28 | Icon UPLOAD = IconLoader.getIcon("/icons/upload.svg", DocViewIcons.class);
29 |
30 | /**
31 | * 下载
32 | */
33 | Icon DOWNLOAD = IconLoader.getIcon("/icons/download.svg", DocViewIcons.class);
34 |
35 | /**
36 | * pin
37 | */
38 | Icon PIN = IconLoader.getIcon("/icons/pin.svg", DocViewIcons.class);
39 |
40 | /**
41 | * editorPreview
42 | */
43 | Icon EDITOR_PREVIEW = IconLoader.getIcon("/icons/editorPreview.svg", DocViewIcons.class);
44 |
45 | /**
46 | * copy
47 | */
48 | Icon COPY = IconLoader.getIcon("/icons/copy.svg", DocViewIcons.class);
49 |
50 | /**
51 | * settings
52 | */
53 | Icon SETTINGS = IconLoader.getIcon("/icons/settings.svg", DocViewIcons.class);
54 |
55 | /**
56 | * checked
57 | */
58 | Icon CHECKED = IconLoader.getIcon("/icons/checked.svg", DocViewIcons.class);
59 |
60 | /**
61 | * json
62 | */
63 | Icon JSON = IconLoader.getIcon("/icons/json.svg", DocViewIcons.class);
64 |
65 | /**
66 | * refresh
67 | */
68 | Icon REFRESH = IconLoader.getIcon("/icons/refresh.svg", DocViewIcons.class);
69 |
70 | /**
71 | * export
72 | */
73 | Icon EXPORT = IconLoader.getIcon("/icons/export.svg", DocViewIcons.class);
74 |
75 | /**
76 | * expand ALL
77 | */
78 | Icon EXPAND_ALL = IconLoader.getIcon("/icons/expandAll.svg", DocViewIcons.class);
79 |
80 | /**
81 | * collapseAll
82 | */
83 | Icon COLLAPSE_ALL = IconLoader.getIcon("/icons/collapseAll.svg", DocViewIcons.class);
84 |
85 | /**
86 | * httpAPI
87 | */
88 | Icon HTTP_API = IconLoader.getIcon("/icons/httpAPI.svg", DocViewIcons.class);
89 |
90 | }
91 |
--------------------------------------------------------------------------------
/src/main/java/com/liuzhihang/doc/view/constant/ValidationConstant.java:
--------------------------------------------------------------------------------
1 | package com.liuzhihang.doc.view.constant;
2 |
3 | /**
4 | * @author liuzhihang
5 | * @date 2020/3/4 22:34
6 | */
7 | public final class ValidationConstant {
8 |
9 | private ValidationConstant() {
10 | }
11 |
12 | public static final String VALID = "javax.validation.Valid";
13 |
14 | public static final String CONSTRAINTS = "javax.validation.constraints";
15 | public static final String ASSERT_FALSE = "javax.validation.constraints.AssertFalse";
16 | public static final String ASSERT_TRUE = "javax.validation.constraints.AssertTrue";
17 | public static final String DECIMAL_MAX = "javax.validation.constraints.DecimalMax";
18 | public static final String DECIMAL_MIN = "javax.validation.constraints.DecimalMin";
19 | public static final String DIGITS = "javax.validation.constraints.Digits";
20 | public static final String EMAIL = "javax.validation.constraints.Email";
21 | public static final String FUTURE = "javax.validation.constraints.Future";
22 | public static final String FUTURE_OR_PRESENT = "javax.validation.constraints.FutureOrPresent";
23 | public static final String MAX = "javax.validation.constraints.Max";
24 | public static final String MIN = "javax.validation.constraints.Min";
25 | public static final String NEGATIVE = "javax.validation.constraints.Negative";
26 | public static final String NEGATIVE_OR_ZERO = "javax.validation.constraints.NegativeOrZero";
27 | public static final String NOT_BLANK = "javax.validation.constraints.NotBlank";
28 | public static final String NOT_EMPTY = "javax.validation.constraints.NotEmpty";
29 | public static final String NOT_NULL = "javax.validation.constraints.NotNull";
30 | public static final String NULL = "javax.validation.constraints.Null";
31 | public static final String PAST = "javax.validation.constraints.Past";
32 | public static final String PAST_OR_PRESENT = "javax.validation.constraints.PastOrPresent";
33 | public static final String PATTERN = "javax.validation.constraints.Pattern";
34 | public static final String POSITIVE = "javax.validation.constraints.Positive";
35 | public static final String POSITIVE_OR_ZERO = "javax.validation.constraints.PositiveOrZero";
36 | public static final String SIZE = "javax.validation.constraints.Size";
37 |
38 | }
39 |
--------------------------------------------------------------------------------
/src/main/java/com/liuzhihang/doc/view/utils/GsonFormatUtil.java:
--------------------------------------------------------------------------------
1 | package com.liuzhihang.doc.view.utils;
2 |
3 | import com.google.gson.Gson;
4 | import com.google.gson.GsonBuilder;
5 | import com.google.gson.JsonElement;
6 | import com.google.gson.JsonNull;
7 | import com.google.gson.internal.Streams;
8 | import com.google.gson.stream.JsonWriter;
9 | import org.jetbrains.annotations.NotNull;
10 |
11 | import java.io.IOException;
12 | import java.io.StringWriter;
13 | import java.io.Writer;
14 | import java.util.Collection;
15 |
16 | /**
17 | * 对 Gson 进行修改主要是修改 newJsonWriter中的缩进
18 | *
19 | * @author liuzhihang
20 | * @date 2019/5/9 11:07
21 | */
22 | public class GsonFormatUtil {
23 |
24 | @NotNull
25 | public static String gsonFormat(Gson gson, JsonElement jsonElement) throws IOException {
26 | StringWriter writer = new StringWriter();
27 | JsonWriter jsonWriter = newJsonWriter(Streams.writerForAppendable(Streams.writerForAppendable(writer)));
28 | gson.toJson(jsonElement, jsonWriter);
29 | return writer.toString();
30 | }
31 |
32 | public static String gsonFormat(Object src) {
33 |
34 | Gson gson = new GsonBuilder().serializeNulls().create();
35 |
36 | return gsonFormat(gson, src);
37 | }
38 |
39 | @NotNull
40 | public static String gsonFormat(Gson gson, Object src) {
41 | if (src == null) {
42 | return gson.toJson(JsonNull.INSTANCE);
43 | }
44 | try {
45 | StringWriter writer = new StringWriter();
46 | JsonWriter jsonWriter = newJsonWriter(Streams.writerForAppendable(Streams.writerForAppendable(writer)));
47 | gson.toJson(src, src.getClass(), jsonWriter);
48 | return writer.toString();
49 | } catch (IOException e) {
50 | if (src instanceof Collection) {
51 | return "[]";
52 | }
53 | return "{}";
54 | }
55 | }
56 |
57 | /**
58 | * 重新JsonWriter的缩进
59 | * 具体请查看相关源码
60 | *
61 | * @param writer
62 | * @return
63 | * @throws IOException
64 | * @see Gson#newJsonWriter(Writer)
65 | */
66 | private static JsonWriter newJsonWriter(Writer writer) throws IOException {
67 | JsonWriter jsonWriter = new JsonWriter(writer);
68 | // 修改此处缩进为四个空格
69 | jsonWriter.setIndent(" ");
70 | jsonWriter.setSerializeNulls(false);
71 | return jsonWriter;
72 | }
73 |
74 |
75 | }
76 |
--------------------------------------------------------------------------------
/src/main/java/com/liuzhihang/doc/view/action/toolbar/window/WindowUploadAction.java:
--------------------------------------------------------------------------------
1 | package com.liuzhihang.doc.view.action.toolbar.window;
2 |
3 | import com.intellij.openapi.actionSystem.AnActionEvent;
4 | import com.intellij.openapi.actionSystem.PlatformDataKeys;
5 | import com.intellij.openapi.project.Project;
6 | import com.intellij.openapi.ui.popup.JBPopupFactory;
7 | import com.intellij.openapi.ui.popup.PopupStep;
8 | import com.intellij.openapi.ui.popup.util.BaseListPopupStep;
9 | import com.liuzhihang.doc.view.DocViewBundle;
10 | import com.liuzhihang.doc.view.action.toolbar.AbstractToolbarUploadAction;
11 | import com.liuzhihang.doc.view.data.DocViewDataKeys;
12 | import com.liuzhihang.doc.view.notification.DocViewNotification;
13 | import com.liuzhihang.doc.view.service.DocViewUploadService;
14 | import com.liuzhihang.doc.view.ui.window.RootNode;
15 | import org.jetbrains.annotations.NotNull;
16 | import org.jetbrains.annotations.Nullable;
17 |
18 | import javax.swing.*;
19 |
20 | /**
21 | * @author liuzhihang
22 | * @date 2021/10/23 19:55
23 | */
24 | public class WindowUploadAction extends AbstractToolbarUploadAction {
25 |
26 | @Override
27 | public void actionPerformed(@NotNull AnActionEvent e) {
28 |
29 | // 获取当前project对象
30 | Project project = e.getData(PlatformDataKeys.PROJECT);
31 | JComponent toolbar = e.getData(DocViewDataKeys.WINDOW_TOOLBAR);
32 | RootNode rootNode = e.getData(DocViewDataKeys.WINDOW_ROOT_NODE);
33 |
34 | if (project == null || toolbar == null || rootNode == null || rootNode.getChildCount() == 0) {
35 | DocViewNotification.notifyError(project, DocViewBundle.message("notify.window.upload.empty"));
36 | return;
37 | }
38 |
39 | JBPopupFactory.getInstance()
40 | .createListPopup(new BaseListPopupStep<>(null, DocViewUploadService.UPLOAD_OPTIONS) {
41 | @Override
42 | public @NotNull String getTextFor(String value) {
43 | return "Upload to " + value;
44 | }
45 |
46 | @Override
47 | public @Nullable PopupStep> onChosen(String selectedValue, boolean finalChoice) {
48 |
49 | DocViewUploadService.getInstance(selectedValue).upload(project, rootNode.docViewList());
50 |
51 | return FINAL_CHOICE;
52 | }
53 | }).showUnderneathOf(toolbar);
54 |
55 |
56 | }
57 |
58 |
59 | }
60 |
--------------------------------------------------------------------------------
/src/main/java/com/liuzhihang/doc/view/ui/ShowDocSettingForm.java:
--------------------------------------------------------------------------------
1 | package com.liuzhihang.doc.view.ui;
2 |
3 | import com.intellij.openapi.options.ConfigurationException;
4 | import com.intellij.openapi.project.Project;
5 | import com.intellij.ui.IdeBorderFactory;
6 | import com.intellij.ui.components.JBTextField;
7 | import com.liuzhihang.doc.view.DocViewBundle;
8 | import com.liuzhihang.doc.view.config.ShowDocSettings;
9 |
10 | import javax.swing.*;
11 |
12 | public class ShowDocSettingForm {
13 | private JPanel rootPanel;
14 |
15 | private JPanel showDocProjectPanel;
16 | private JBTextField urlTextField;
17 | private JBTextField apiKeyTextField;
18 | private JBTextField apiTokenTextField;
19 |
20 |
21 | private final Project project;
22 |
23 | public ShowDocSettingForm(Project project) {
24 | this.project = project;
25 | showDocProjectPanel.setBorder(IdeBorderFactory.createTitledBorder(DocViewBundle.message("showdoc.project.panel")));
26 | }
27 |
28 | public JPanel getRootPanel() {
29 | return rootPanel;
30 | }
31 |
32 |
33 | public boolean isModified() {
34 |
35 | ShowDocSettings settings = ShowDocSettings.getInstance(project);
36 |
37 | if (!urlTextField.getText().equals(settings.getUrl())) {
38 | return true;
39 | }
40 | if (!apiKeyTextField.getText().equals(settings.getApiKey())) {
41 | return true;
42 | }
43 |
44 | if (!apiTokenTextField.getText().equals(settings.getApiToken())) {
45 | return true;
46 | }
47 |
48 | return false;
49 | }
50 |
51 | public void apply() throws ConfigurationException {
52 | ShowDocSettings settings = ShowDocSettings.getInstance(project);
53 | String urlTextFieldText = urlTextField.getText();
54 |
55 | if (urlTextFieldText.endsWith("/")) {
56 | settings.setUrl(urlTextFieldText.substring(0, urlTextFieldText.length() - 1));
57 | } else {
58 | settings.setUrl(urlTextFieldText);
59 | }
60 | settings.setApiKey(apiKeyTextField.getText());
61 | settings.setApiToken(apiTokenTextField.getText());
62 |
63 | }
64 |
65 | public void reset() {
66 |
67 | ShowDocSettings settings = ShowDocSettings.getInstance(project);
68 |
69 | urlTextField.setText(settings.getUrl());
70 | apiKeyTextField.setText(settings.getApiKey());
71 | apiTokenTextField.setText(settings.getApiToken());
72 | }
73 |
74 | }
75 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Created by .ignore support plugin (hsz.mobi)
2 | ### Example user template template
3 | ### Example user template
4 |
5 | # IntelliJ project files
6 | .idea
7 | *.iml
8 | out
9 | gen
10 | ### Gradle template
11 | .gradle
12 | **/build/
13 | !src/**/build/
14 |
15 | # Ignore Gradle GUI config
16 | gradle-app.setting
17 |
18 | # Avoid ignoring Gradle wrapper jar file (.jar files are usually ignored)
19 | !gradle-wrapper.jar
20 |
21 | # Cache of project
22 | .gradletasknamecache
23 |
24 | # # Work around https://youtrack.jetbrains.com/issue/IDEA-116898
25 | # gradle/wrapper/gradle-wrapper.properties
26 |
27 | ### JetBrains template
28 | # Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio, WebStorm and Rider
29 | # Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839
30 |
31 | # User-specific stuff
32 | .idea/**/workspace.xml
33 | .idea/**/tasks.xml
34 | .idea/**/usage.statistics.xml
35 | .idea/**/dictionaries
36 | .idea/**/shelf
37 |
38 | # Generated files
39 | .idea/**/contentModel.xml
40 |
41 | # Sensitive or high-churn files
42 | .idea/**/dataSources/
43 | .idea/**/dataSources.ids
44 | .idea/**/dataSources.local.xml
45 | .idea/**/sqlDataSources.xml
46 | .idea/**/dynamic.xml
47 | .idea/**/uiDesigner.xml
48 | .idea/**/dbnavigator.xml
49 |
50 | # Gradle
51 | .idea/**/gradle.xml
52 | .idea/**/libraries
53 |
54 | # Gradle and Maven with auto-import
55 | # When using Gradle or Maven with auto-import, you should exclude module files,
56 | # since they will be recreated, and may cause churn. Uncomment if using
57 | # auto-import.
58 | # .idea/artifacts
59 | # .idea/compiler.xml
60 | # .idea/jarRepositories.xml
61 | # .idea/modules.xml
62 | # .idea/*.iml
63 | # .idea/modules
64 | # *.iml
65 | # *.ipr
66 |
67 | # CMake
68 | cmake-build-*/
69 |
70 | # Mongo Explorer plugin
71 | .idea/**/mongoSettings.xml
72 |
73 | # File-based project format
74 | *.iws
75 |
76 | # IntelliJ
77 | out/
78 |
79 | # mpeltonen/sbt-idea plugin
80 | .idea_modules/
81 |
82 | # JIRA plugin
83 | atlassian-ide-plugin.xml
84 |
85 | # Cursive Clojure plugin
86 | .idea/replstate.xml
87 |
88 | # Crashlytics plugin (for Android Studio and IntelliJ)
89 | com_crashlytics_export_strings.xml
90 | crashlytics.properties
91 | crashlytics-build.properties
92 | fabric.properties
93 |
94 | # Editor-based Rest Client
95 | .idea/httpRequests
96 |
97 | # Android studio 3.1+ serialized cache file
98 | .idea/caches/build_file_checksums.ser
99 |
100 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | Doc View
2 | =======
3 |
4 | [](https://plugins.jetbrains.com/plugin/15305-doc-view)
5 | [](https://plugins.jetbrains.com/plugin/15305-doc-view/versions)
6 | [](https://plugins.jetbrains.com/plugin/15305-doc-view)
7 | [](https://github.com/liuzhihang/toolkit/blob/master/LICENSE)
8 |
9 | 特征
10 | ----
11 |
12 | - [x] Controller/Dubbo 接口文档生成
13 | - [x] 支持 validation、swagger 等注解
14 | - [x] Markdown 接口查看、预览、复制、导出
15 | - [x] 支持自定义生成接口的 Markdown 模版
16 | - [x] 支持界面编辑文档、注释、并同步保存到代码注释或 Swagger 注解中
17 | - [x] 支持在编辑实体界面, 将实体复制为 Json 字符串
18 | - [x] 支持上传文档到 YApi
19 | - [x] 支持上传文档到 ShowDoc
20 | - [x] 支持自定义配置
21 |
22 | 演示
23 | ----
24 |
25 | 
26 | 
27 |
28 | [更多截图演示](https://github.com/liuzhihang/doc-view/discussions/17)
29 |
30 | 安装
31 | ----
32 |
33 | - **在线安装:**
34 | - `File` -> `Setting` -> `Plugins` -> 搜索 `Doc View`
35 |
36 | - **手动安装:**
37 | - [下载插件](https://github.com/liuzhihang/doc-view/releases) -> `File` -> `Setting` -> `Plugins`
38 | -> `Install Plugin from Disk...`
39 |
40 | 使用
41 | ----
42 |
43 | - 右键菜单选择 `Doc View`
44 |
45 | 更新
46 | ----
47 |
48 | [查看历史更新记录](https://github.com/liuzhihang/doc-view/releases)
49 |
50 | 关于我
51 | ----
52 |
53 | 欢迎关注公众号:『 程序员小航 』
54 |
55 | 
56 |
57 |
58 | 小伙伴们
59 | ----
60 |
61 | 感谢以下小伙伴的参与:
62 |
63 | [lvgo](https://github.com/lvgocc)
64 | [知一](https://github.com/zh-d-d)
65 | [大斌](https://github.com/dabinaa)
66 | [ayang0422](https://github.com/ayang0422)
67 |
68 |
69 |
70 | 其他插件
71 | ----
72 |
73 | Toolkit: [https://github.com/liuzhihang/toolkit](https://github.com/liuzhihang/toolkit)
74 |
75 |
76 | copy-as-json: [https://github.com/liuzhihang/copy-as-json](https://github.com/liuzhihang/copy-as-json)
77 |
78 | 本工具使用 JetBrains IDEA 进行开发
79 | ----
80 | 
81 |
82 |
83 |
--------------------------------------------------------------------------------
/src/main/java/com/liuzhihang/doc/view/integration/impl/YuQueFacadeServiceImpl.java:
--------------------------------------------------------------------------------
1 | package com.liuzhihang.doc.view.integration.impl;
2 |
3 | import com.google.gson.Gson;
4 | import com.google.gson.GsonBuilder;
5 | import com.liuzhihang.doc.view.integration.YuQueFacadeService;
6 | import com.liuzhihang.doc.view.integration.dto.YuQueCreate;
7 | import com.liuzhihang.doc.view.integration.dto.YuQueResponse;
8 | import com.liuzhihang.doc.view.integration.dto.YuQueUpdate;
9 | import com.liuzhihang.doc.view.utils.HttpUtils;
10 | import org.apache.commons.lang3.StringUtils;
11 | import org.apache.http.Header;
12 | import org.apache.http.message.BasicHeader;
13 |
14 | import java.util.List;
15 |
16 | /**
17 | * @author liuzhihang
18 | * @date 2022/3/31 23:16
19 | */
20 | public class YuQueFacadeServiceImpl implements YuQueFacadeService {
21 |
22 | private static final Gson gson = new GsonBuilder().serializeNulls().create();
23 |
24 | @Override
25 | public YuQueResponse getDoc(String url, String token, String namespace, String slug) throws Exception {
26 |
27 | Header header = new BasicHeader("X-Auth-Token", token);
28 |
29 |
30 | String resp = null;
31 | try {
32 | resp = HttpUtils.get(url + "/repos/" + namespace + "/docs/" + slug, null, List.of(header));
33 | } catch (RuntimeException e) {
34 | String message = e.getMessage();
35 | if (message.contains("404") && message.contains("Not Found")) {
36 | return null;
37 | }
38 | }
39 |
40 | return gson.fromJson(resp, YuQueResponse.class);
41 | }
42 |
43 | @Override
44 | public YuQueResponse create(String url, String token, String namespace, YuQueCreate yuQueCreate) throws Exception {
45 |
46 | Header header = new BasicHeader("X-Auth-Token", token);
47 |
48 | String resp = HttpUtils.post(url + "/repos/" + namespace + "/docs/", gson.toJson(yuQueCreate), List.of(header));
49 |
50 | if (StringUtils.isBlank(resp)) {
51 | throw new Exception("语雀接口返回为空");
52 | }
53 | return gson.fromJson(resp, YuQueResponse.class);
54 | }
55 |
56 | @Override
57 | public YuQueResponse update(String url, String token, String namespace, Long id, YuQueUpdate yuQueUpdate) throws Exception {
58 |
59 | Header header = new BasicHeader("X-Auth-Token", token);
60 |
61 | String resp = HttpUtils.put(url + "/repos/" + namespace + "/docs/" + id, gson.toJson(yuQueUpdate), List.of(header));
62 |
63 | if (StringUtils.isBlank(resp)) {
64 | throw new Exception("语雀接口返回为空");
65 | }
66 | return gson.fromJson(resp, YuQueResponse.class);
67 | }
68 | }
69 |
--------------------------------------------------------------------------------
/src/main/java/com/liuzhihang/doc/view/dto/DocView.java:
--------------------------------------------------------------------------------
1 | package com.liuzhihang.doc.view.dto;
2 |
3 | import com.intellij.psi.PsiClass;
4 | import com.intellij.psi.PsiMethod;
5 | import com.liuzhihang.doc.view.enums.ContentTypeEnum;
6 | import com.liuzhihang.doc.view.enums.FrameworkEnum;
7 | import lombok.Data;
8 |
9 | import java.util.List;
10 |
11 | /**
12 | * 文档参数
13 | *
14 | * @author liuzhihang
15 | * @date 2020/2/28 10:32
16 | */
17 | @Data
18 | public class DocView {
19 |
20 | /**
21 | * 当前接口所在的类
22 | */
23 | private PsiClass psiClass;
24 |
25 | /**
26 | * 当前接口的方法
27 | */
28 | private PsiMethod psiMethod;
29 |
30 | /**
31 | * 文档标题, 方法所属的类
32 | */
33 | private String docTitle;
34 |
35 | /**
36 | * 接口方法所属类的标签
37 | *
38 | * swagger @Api(tags = {"用户接口相关", "用户11"})
39 | * swagger3 @Tags
40 | */
41 | private String[] classTags;
42 |
43 | /**
44 | * 接口方法的标签
45 | *
46 | * swagger @ApiOperation(value = "查询用户", tags = "用户接口 xxx")
47 | * swagger3 @Operation(summary = "用户接口 1", tags = "测试")
48 | */
49 | private String[] tags;
50 |
51 | /**
52 | * 文档名称
53 | */
54 | private String name;
55 |
56 | /**
57 | * 文档描述
58 | */
59 | private String desc;
60 |
61 | /**
62 | * 环境地址
63 | */
64 | private List domain;
65 |
66 | /**
67 | * 接口地址
68 | */
69 | private String path;
70 |
71 | /**
72 | * 请求方式 GET POST PUT DELETE HEAD OPTIONS PATCH
73 | */
74 | private String method;
75 |
76 | /**
77 | * 变动说明
78 | */
79 | private String changeLog;
80 |
81 | /**
82 | * headers
83 | */
84 | private List headerList;
85 |
86 | /**
87 | * 请求参数
88 | */
89 | private Body reqBody = new Body();
90 |
91 | /**
92 | * 返回参数
93 | */
94 | private Body respBody = new Body();
95 |
96 | /**
97 | * 请求参数
98 | */
99 | private List reqParamList;
100 |
101 | /**
102 | * body 参数
103 | */
104 | private String reqBodyExample;
105 |
106 | /**
107 | * form 参数
108 | */
109 | private String reqFormExample;
110 |
111 | /**
112 | * 请求参数类型 json/form
113 | */
114 | private ContentTypeEnum contentType;
115 |
116 | /**
117 | * 返回参数
118 | */
119 | private String respExample;
120 |
121 | /**
122 | * 备注
123 | */
124 | private String remark;
125 |
126 | private FrameworkEnum type;
127 |
128 | public DocView(String name) {
129 | this.name = name;
130 | }
131 |
132 | public DocView() {
133 | }
134 |
135 | }
136 |
--------------------------------------------------------------------------------
/src/main/java/com/liuzhihang/doc/view/action/toolbar/preview/PreviewRightUploadAction.java:
--------------------------------------------------------------------------------
1 | package com.liuzhihang.doc.view.action.toolbar.preview;
2 |
3 | import com.intellij.openapi.actionSystem.AnActionEvent;
4 | import com.intellij.openapi.actionSystem.PlatformDataKeys;
5 | import com.intellij.openapi.project.Project;
6 | import com.intellij.openapi.ui.popup.JBPopup;
7 | import com.intellij.openapi.ui.popup.JBPopupFactory;
8 | import com.intellij.openapi.ui.popup.PopupStep;
9 | import com.intellij.openapi.ui.popup.util.BaseListPopupStep;
10 | import com.liuzhihang.doc.view.action.toolbar.AbstractToolbarUploadAction;
11 | import com.liuzhihang.doc.view.data.DocViewDataKeys;
12 | import com.liuzhihang.doc.view.dto.DocView;
13 | import com.liuzhihang.doc.view.service.DocViewUploadService;
14 | import com.liuzhihang.doc.view.ui.PreviewForm;
15 | import org.jetbrains.annotations.NotNull;
16 | import org.jetbrains.annotations.Nullable;
17 |
18 | import javax.swing.*;
19 | import java.awt.*;
20 |
21 | /**
22 | * Preview 右侧单个上传
23 | *
24 | * @author liuzhihang
25 | * @date 2021/10/23 22:31
26 | */
27 | public class PreviewRightUploadAction extends AbstractToolbarUploadAction {
28 | @Override
29 | public void actionPerformed(@NotNull AnActionEvent e) {
30 |
31 | // 获取当前project对象
32 | Project project = e.getData(PlatformDataKeys.PROJECT);
33 | JBPopup popup = e.getData(DocViewDataKeys.PREVIEW_POPUP);
34 | DocView currentDocView = e.getData(DocViewDataKeys.PREVIEW_CURRENT_DOC_VIEW);
35 | JPanel previewToolbarPanel = e.getData(DocViewDataKeys.PREVIEW_TOOLBAR_PANEL);
36 |
37 |
38 | if (popup == null || project == null || currentDocView == null || previewToolbarPanel == null) {
39 | return;
40 | }
41 |
42 | Point location = previewToolbarPanel.getLocationOnScreen();
43 | location.x = MouseInfo.getPointerInfo().getLocation().x;
44 | location.y += previewToolbarPanel.getHeight();
45 |
46 | PreviewForm.myIsPinned.set(true);
47 |
48 | JBPopupFactory.getInstance()
49 | .createListPopup(new BaseListPopupStep<>(null, DocViewUploadService.UPLOAD_OPTIONS) {
50 |
51 | @Override
52 | public @NotNull String getTextFor(String value) {
53 | return "Upload to " + value;
54 | }
55 |
56 | @Override
57 | public @Nullable PopupStep> onChosen(String selectedValue, boolean finalChoice) {
58 |
59 | DocViewUploadService.getInstance(selectedValue).doUpload(project, currentDocView);
60 |
61 | return FINAL_CHOICE;
62 | }
63 | }).showInScreenCoordinates(previewToolbarPanel, location);
64 |
65 | }
66 |
67 | }
68 |
--------------------------------------------------------------------------------
/src/main/java/com/liuzhihang/doc/view/dom/DubboDefinitionSearch.java:
--------------------------------------------------------------------------------
1 | package com.liuzhihang.doc.view.dom;
2 |
3 | import com.intellij.openapi.application.QueryExecutorBase;
4 | import com.intellij.openapi.project.Project;
5 | import com.intellij.psi.PsiClass;
6 | import com.intellij.psi.PsiElement;
7 | import com.intellij.psi.PsiTypeParameterListOwner;
8 | import com.intellij.psi.search.GlobalSearchScope;
9 | import com.intellij.psi.search.searches.DefinitionsScopedSearch;
10 | import com.intellij.psi.xml.XmlElement;
11 | import com.intellij.util.Processor;
12 | import com.intellij.util.xml.DomElement;
13 | import com.intellij.util.xml.DomFileElement;
14 | import com.intellij.util.xml.DomService;
15 | import org.jetbrains.annotations.NotNull;
16 |
17 | import java.util.List;
18 | import java.util.Objects;
19 |
20 | /**
21 | * 加载所有 xml 中的 dubbo 接口
22 | *
23 | * @author liuzhihang
24 | * @date 2022-04-12 00:05:11
25 | */
26 | public class DubboDefinitionSearch extends QueryExecutorBase {
27 |
28 | public DubboDefinitionSearch() {
29 | super(true);
30 | }
31 |
32 | @Override
33 | public void processQuery(@NotNull DefinitionsScopedSearch.SearchParameters parameters,
34 | @NotNull Processor super XmlElement> consumer) {
35 |
36 | PsiElement element = parameters.getElement();
37 |
38 | if (element instanceof PsiTypeParameterListOwner) {
39 | Processor processor = domElement -> consumer.process(domElement.getXmlElement());
40 | if (element instanceof PsiClass) {
41 | PsiClass psiClass = (PsiClass) element;
42 | Project project = psiClass.getProject();
43 | // 当前项目的所有元素 beans
44 | List> fileElements = DomService.getInstance()
45 | .getFileElements(BeansDomElement.class, project, GlobalSearchScope.allScope(project));
46 | // 只需要判断 interface
47 | String qualifiedName = psiClass.getQualifiedName();
48 |
49 | for (DomFileElement beansDomFileElement : fileElements) {
50 | BeansDomElement rootElement = beansDomFileElement.getRootElement();
51 |
52 | for (DubboServiceDomElement dubboServiceDomElement : rootElement.getDubboServiceDomElements()) {
53 | String interfaceQualifiedName = dubboServiceDomElement.getInterface().getStringValue();
54 | if (Objects.equals(qualifiedName, interfaceQualifiedName)) {
55 | processor.process(dubboServiceDomElement);
56 | }
57 | }
58 | }
59 | }
60 | }
61 |
62 | }
63 | }
64 |
--------------------------------------------------------------------------------
/src/main/resources/icons/settings.svg:
--------------------------------------------------------------------------------
1 |
2 |
7 |
--------------------------------------------------------------------------------
/src/main/resources/icons/settings_dark.svg:
--------------------------------------------------------------------------------
1 |
2 |
7 |
--------------------------------------------------------------------------------
/src/main/java/com/liuzhihang/doc/view/integration/impl/YApiFacadeServiceImpl.java:
--------------------------------------------------------------------------------
1 | package com.liuzhihang.doc.view.integration.impl;
2 |
3 | import com.google.gson.Gson;
4 | import com.google.gson.GsonBuilder;
5 | import com.google.gson.JsonObject;
6 | import com.google.gson.reflect.TypeToken;
7 | import com.liuzhihang.doc.view.integration.YApiFacadeService;
8 | import com.liuzhihang.doc.view.integration.dto.YApiCat;
9 | import com.liuzhihang.doc.view.integration.dto.YApiResponse;
10 | import com.liuzhihang.doc.view.integration.dto.YapiSave;
11 | import com.liuzhihang.doc.view.utils.HttpUtils;
12 | import lombok.extern.slf4j.Slf4j;
13 | import org.apache.commons.lang3.StringUtils;
14 |
15 | import java.lang.reflect.Type;
16 | import java.util.List;
17 |
18 | /**
19 | * @author liuzhihang
20 | * @date 2021/6/8 19:20
21 | */
22 | @Slf4j
23 | public class YApiFacadeServiceImpl implements YApiFacadeService {
24 |
25 | private static final Gson gson = new GsonBuilder().serializeNulls().create();
26 |
27 | @Override
28 | public void save(YapiSave save) throws Exception {
29 |
30 | String resp = HttpUtils.post(save.getYapiUrl() + "/api/interface/save", gson.toJson(save));
31 |
32 | if (StringUtils.isBlank(resp)) {
33 | throw new Exception("YApi 接口返回为空");
34 | }
35 |
36 | JsonObject jsonObject = gson.fromJson(resp, JsonObject.class);
37 |
38 | if (jsonObject.get("errcode").getAsInt() != 0) {
39 | throw new Exception("YApi 接口返回失败:" + resp);
40 | }
41 | }
42 |
43 | @Override
44 | public List getCatMenu(String yapiUrl, Long projectId, String token) throws Exception {
45 |
46 | String url = yapiUrl + "/api/interface/getCatMenu" +
47 | "?project_id=" + projectId +
48 | "&token=" + token;
49 |
50 | String resp = HttpUtils.get(url);
51 |
52 | Type jsonType = new TypeToken>>() {
53 | }.getType();
54 |
55 | YApiResponse> response = gson.fromJson(resp, jsonType);
56 |
57 | if (response.getErrcode() != 0) {
58 | throw new Exception("YApi 接口返回失败:" + resp);
59 | }
60 | return response.getData();
61 | }
62 |
63 | @Override
64 | public YApiCat addCat(YApiCat cat) throws Exception {
65 |
66 | String resp = HttpUtils.post(cat.getYapiUrl() + "/api/interface/add_cat", gson.toJson(cat));
67 |
68 | if (StringUtils.isBlank(resp)) {
69 | throw new Exception("YApi 接口返回为空");
70 | }
71 |
72 | Type jsonType = new TypeToken>() {
73 | }.getType();
74 |
75 | YApiResponse response = gson.fromJson(resp, jsonType);
76 |
77 | if (response == null || response.getErrcode() != 0) {
78 | throw new Exception("YApi 接口返回失败:" + resp);
79 | }
80 | return response.getData();
81 |
82 | }
83 | }
84 |
--------------------------------------------------------------------------------
/src/main/java/com/liuzhihang/doc/view/ui/window/MethodNode.java:
--------------------------------------------------------------------------------
1 | package com.liuzhihang.doc.view.ui.window;
2 |
3 | import com.intellij.openapi.project.Project;
4 | import com.intellij.psi.PsiClass;
5 | import com.intellij.psi.PsiMethod;
6 | import com.intellij.ui.treeStructure.SimpleNode;
7 | import com.intellij.ui.treeStructure.SimpleTree;
8 | import com.liuzhihang.doc.view.dto.DocView;
9 | import com.liuzhihang.doc.view.service.DocViewService;
10 | import com.liuzhihang.doc.view.utils.CustomFileUtils;
11 | import com.liuzhihang.doc.view.utils.DocViewUtils;
12 |
13 | import java.awt.event.InputEvent;
14 | import java.util.Collections;
15 | import java.util.List;
16 |
17 | /**
18 | * 目录树上的一个节点
19 | *
20 | * @author liuzhihang
21 | * @date 2022/4/4
22 | */
23 | public class MethodNode extends DocViewNode {
24 |
25 | private final PsiMethod psiMethod;
26 | private final PsiClass psiClass;
27 |
28 | protected MethodNode(SimpleNode aParent, PsiClass psiClass, PsiMethod psiMethod) {
29 | super(aParent);
30 | this.psiMethod = psiMethod;
31 | this.psiClass = psiClass;
32 |
33 | getTemplatePresentation().setIcon(null);
34 | getTemplatePresentation().setTooltip(DocViewUtils.getMethodDesc(psiMethod));
35 | }
36 |
37 |
38 | @Override
39 | protected SimpleNode[] buildChildren() {
40 | return new SimpleNode[0];
41 | }
42 |
43 | @Override
44 | public String getName() {
45 | return DocViewUtils.getName(psiMethod);
46 | }
47 |
48 | @Override
49 | public List docViewList() {
50 | DocViewService service = DocViewService.getInstance(psiClass.getProject(), psiClass);
51 | return Collections.singletonList(service.buildClassMethodDoc(psiClass, psiMethod));
52 |
53 | }
54 |
55 | @Override
56 | public void updateNode(Project project) {
57 |
58 | }
59 |
60 | @Override
61 | public String docPath(Project project) {
62 |
63 | ClassNode classNode = (ClassNode) getParent();
64 |
65 | return classNode.docPath(project) + "/" + DocViewUtils.getName(psiMethod) + ".md";
66 |
67 | }
68 |
69 | @Override
70 | public String httpPath(Project project) {
71 |
72 | ClassNode classNode = (ClassNode) getParent();
73 |
74 | return classNode.httpPath(project) + "/" + DocViewUtils.getName(psiMethod) + ".http";
75 | }
76 |
77 | @Override
78 | public void handleSelection(SimpleTree tree) {
79 | super.handleSelection(tree);
80 | }
81 |
82 | /**
83 | * 被双击或者 Enter 时, 双击打开文档
84 | *
85 | * @param tree
86 | * @param inputEvent
87 | */
88 | @Override
89 | public void handleDoubleClickOrEnter(SimpleTree tree, InputEvent inputEvent) {
90 | CustomFileUtils.openMd(psiClass.getProject(), this);
91 | }
92 |
93 | public PsiMethod getPsiMethod() {
94 | return psiMethod;
95 | }
96 |
97 | public PsiClass getPsiClass() {
98 | return psiClass;
99 | }
100 |
101 | }
--------------------------------------------------------------------------------
/src/main/java/com/liuzhihang/doc/view/integration/dto/YapiSave.java:
--------------------------------------------------------------------------------
1 | package com.liuzhihang.doc.view.integration.dto;
2 |
3 | import com.google.gson.annotations.SerializedName;
4 | import lombok.Data;
5 |
6 | import java.io.Serializable;
7 | import java.util.List;
8 |
9 | /**
10 | * 新增或上传对象
11 | *
12 | * https://hellosean1025.github.io/yapi/openapi.html
13 | *
14 | * @author liuzhihang
15 | * @date 2021/6/8 20:11
16 | */
17 | @Data
18 | public class YapiSave implements Serializable {
19 |
20 | /**
21 | * 项目信息
22 | */
23 | private String yapiUrl;
24 |
25 | /**
26 | * 项目 token
27 | */
28 | private String token;
29 |
30 | /**
31 | * 项目 id
32 | */
33 | private Long projectId;
34 |
35 | /**
36 | * 接口 id
37 | */
38 | private String id;
39 |
40 | /**
41 | * 品类id
42 | */
43 | @SerializedName("catid")
44 | private Long catId;
45 |
46 | /**
47 | * 请求路径
48 | */
49 | private String path;
50 | /**
51 | * 请求方式
52 | */
53 | private String method;
54 |
55 | /**
56 | * 请求数据类型
57 | * 枚举: raw,form,json
58 | */
59 | @SerializedName("req_body_type")
60 | private String reqBodyType;
61 |
62 | /**
63 | * 请求数据body
64 | */
65 | @SerializedName("req_body_other")
66 | private String reqBodyOther;
67 | /**
68 | * 请求参数body 是否为json_schema
69 | */
70 | @SerializedName("req_body_is_json_schema")
71 | private boolean reqBodyIsJsonSchema;
72 |
73 |
74 | /**
75 | * 请求参数 form 类型
76 | */
77 | @SerializedName("req_body_form")
78 | private List reqBodyForm;
79 |
80 | /**
81 | * 请求参数
82 | */
83 | @SerializedName("req_params")
84 | private List reqParams;
85 |
86 | /**
87 | * 请求参数
88 | */
89 | @SerializedName("req_headers")
90 | private List reqHeaders;
91 |
92 | /**
93 | * 请求参数
94 | */
95 | @SerializedName("req_query")
96 | private List reqQuery;
97 |
98 | /**
99 | * 返回参数类型 json
100 | * 枚举: raw,json
101 | */
102 | @SerializedName("res_body_type")
103 | private String resBodyType = "json";
104 |
105 | /**
106 | * 返回参数
107 | */
108 | @SerializedName("res_body")
109 | private String resBody;
110 |
111 |
112 | /**
113 | * 文档描述
114 | */
115 | private String desc = "";
116 |
117 | /**
118 | * 标题
119 | */
120 | private String title;
121 | /**
122 | * 邮件开关
123 | */
124 | @SerializedName("switch_notice")
125 | private Boolean switchNotice = false;
126 | /**
127 | * 状态 undone,默认done
128 | */
129 | private String status = "undone";
130 |
131 |
132 | /**
133 | * 返回参数是否为json_schema
134 | */
135 | @SerializedName("res_body_is_json_schema")
136 | private boolean resBodyIsJsonSchema = true;
137 |
138 | /**
139 | * 备注信息
140 | */
141 | private String markdown;
142 |
143 |
144 | }
145 |
--------------------------------------------------------------------------------
/src/main/java/com/liuzhihang/doc/view/ui/window/ClassNode.java:
--------------------------------------------------------------------------------
1 | package com.liuzhihang.doc.view.ui.window;
2 |
3 | import com.intellij.icons.AllIcons;
4 | import com.intellij.openapi.project.Project;
5 | import com.intellij.psi.PsiClass;
6 | import com.intellij.psi.PsiMethod;
7 | import com.intellij.ui.treeStructure.SimpleNode;
8 | import com.intellij.ui.treeStructure.SimpleTree;
9 | import com.liuzhihang.doc.view.dto.DocView;
10 | import com.liuzhihang.doc.view.utils.DocViewUtils;
11 |
12 | import java.awt.event.InputEvent;
13 | import java.util.ArrayList;
14 | import java.util.Collection;
15 | import java.util.List;
16 | import java.util.stream.Collectors;
17 |
18 | /**
19 | * 目录树上的一个节点
20 | *
21 | * @author liuzhihang
22 | * @date 2022/4/4
23 | */
24 | public class ClassNode extends DocViewNode {
25 |
26 | private final List methodNodes = new ArrayList<>();
27 | private final PsiClass psiClass;
28 |
29 | protected ClassNode(SimpleNode aParent, PsiClass psiClass) {
30 | super(aParent);
31 | this.psiClass = psiClass;
32 |
33 | getTemplatePresentation().setIcon(psiClass.isInterface() ? AllIcons.Nodes.Interface : AllIcons.Nodes.Class);
34 | getTemplatePresentation().setTooltip(DocViewUtils.getTitle(psiClass));
35 | updateNode(psiClass.getProject());
36 | }
37 |
38 | public void updateNode(Project project) {
39 |
40 | PsiMethod[] methods = psiClass.getMethods();
41 |
42 | for (PsiMethod psiMethod : methods) {
43 | if (DocViewUtils.isDocViewMethod(psiMethod)) {
44 | MethodNode methodNode = new MethodNode(this, psiClass, psiMethod);
45 | methodNodes.add(methodNode);
46 | }
47 | }
48 | update();
49 | }
50 |
51 | @Override
52 | public String docPath(Project project) {
53 |
54 | ModuleNode moduleNode = (ModuleNode) getParent();
55 |
56 | return moduleNode.docPath(project) + "/" + DocViewUtils.getTitle(psiClass);
57 | }
58 |
59 | @Override
60 | public String httpPath(Project project) {
61 |
62 | ModuleNode moduleNode = (ModuleNode) getParent();
63 |
64 | return moduleNode.httpPath(project) + "/" + DocViewUtils.getTitle(psiClass);
65 | }
66 |
67 | @Override
68 | protected SimpleNode[] buildChildren() {
69 | return methodNodes.toArray(new SimpleNode[0]);
70 | }
71 |
72 | @Override
73 | public String getName() {
74 | return DocViewUtils.getTitle(psiClass);
75 | }
76 |
77 | @Override
78 | public List docViewList() {
79 | return methodNodes.stream().map(MethodNode::docViewList).flatMap(Collection::stream).collect(Collectors.toList());
80 | }
81 |
82 | @Override
83 | public void handleSelection(SimpleTree tree) {
84 | super.handleSelection(tree);
85 | }
86 |
87 | /**
88 | * 被双击或者 Enter 时
89 | *
90 | * @param tree
91 | * @param inputEvent
92 | */
93 | @Override
94 | public void handleDoubleClickOrEnter(SimpleTree tree, InputEvent inputEvent) {
95 | super.handleDoubleClickOrEnter(tree, inputEvent);
96 | }
97 | }
--------------------------------------------------------------------------------
/src/main/java/com/liuzhihang/doc/view/action/EditorAction.java:
--------------------------------------------------------------------------------
1 | package com.liuzhihang.doc.view.action;
2 |
3 | import com.intellij.openapi.actionSystem.*;
4 | import com.intellij.openapi.editor.Editor;
5 | import com.intellij.openapi.project.DumbService;
6 | import com.intellij.openapi.project.Project;
7 | import com.intellij.psi.PsiClass;
8 | import com.intellij.psi.PsiFile;
9 | import com.liuzhihang.doc.view.DocViewBundle;
10 | import com.liuzhihang.doc.view.notification.DocViewNotification;
11 | import com.liuzhihang.doc.view.ui.ParamDocEditorForm;
12 | import com.liuzhihang.doc.view.utils.CustomPsiUtils;
13 | import com.liuzhihang.doc.view.utils.DocViewUtils;
14 | import org.jetbrains.annotations.NotNull;
15 |
16 | /**
17 | * 编辑实体类字段注释
18 | *
19 | * @author liuzhihang
20 | * @date 2020/2/26 21:57
21 | */
22 | public class EditorAction extends AbstractAction {
23 |
24 | /**
25 | * @see AnAction#actionPerformed(AnActionEvent)
26 | */
27 | @Override
28 | public void actionPerformed(AnActionEvent e) {
29 |
30 | // 获取当前project对象
31 | Project project = e.getData(PlatformDataKeys.PROJECT);
32 | // 获取当前编辑的文件, 可以进而获取 PsiClass, PsiField 对象
33 | PsiFile psiFile = e.getData(CommonDataKeys.PSI_FILE);
34 | Editor editor = e.getData(CommonDataKeys.EDITOR);
35 |
36 | if (editor == null || project == null || psiFile == null || DumbService.isDumb(project)) {
37 | return;
38 | }
39 |
40 | // 获取Java类或者接口
41 | PsiClass targetClass = CustomPsiUtils.getTargetClass(editor, psiFile);
42 |
43 | if (targetClass == null || targetClass.isAnnotationType() || targetClass.isEnum()) {
44 | DocViewNotification.notifyError(project, DocViewBundle.message("notify.error.class"));
45 | return;
46 | }
47 |
48 | ParamDocEditorForm.getInstance(project, psiFile, editor, targetClass).popup();
49 | }
50 |
51 | /**
52 | * 设置右键菜单是否隐藏 Doc View
53 | *
54 | * @param e
55 | */
56 | @Override
57 | public void update(@NotNull AnActionEvent e) {
58 |
59 | Project project = e.getData(PlatformDataKeys.PROJECT);
60 | PsiFile psiFile = e.getData(CommonDataKeys.PSI_FILE);
61 | Editor editor = e.getData(CommonDataKeys.EDITOR);
62 |
63 | Presentation presentation = e.getPresentation();
64 |
65 | if (editor == null || project == null || psiFile == null || DumbService.isDumb(project)) {
66 | presentation.setEnabledAndVisible(false);
67 | return;
68 | }
69 |
70 | PsiClass targetClass = CustomPsiUtils.getTargetClass(editor, psiFile);
71 |
72 | if (targetClass == null || targetClass.isAnnotationType() || targetClass.isInterface() || targetClass.isEnum()) {
73 | presentation.setEnabledAndVisible(false);
74 | return;
75 | }
76 |
77 | // 判断是否是 Doc View 类,是的话 隐藏
78 | if (DocViewUtils.isDocViewClass(targetClass)) {
79 | presentation.setEnabledAndVisible(false);
80 | return;
81 | }
82 |
83 | presentation.setEnabledAndVisible(true);
84 | }
85 |
86 | @Override
87 | public @NotNull ActionUpdateThread getActionUpdateThread() {
88 | return ActionUpdateThread.BGT;
89 | }
90 |
91 | }
92 |
--------------------------------------------------------------------------------
/src/main/java/com/liuzhihang/doc/view/service/impl/WriterService.java:
--------------------------------------------------------------------------------
1 | package com.liuzhihang.doc.view.service.impl;
2 |
3 | import com.intellij.openapi.command.WriteCommandAction;
4 | import com.intellij.openapi.diagnostic.Logger;
5 | import com.intellij.openapi.editor.Editor;
6 | import com.intellij.openapi.editor.EditorModificationUtil;
7 | import com.intellij.openapi.project.Project;
8 | import com.intellij.psi.PsiElement;
9 | import com.intellij.psi.PsiJavaDocumentedElement;
10 | import com.intellij.psi.codeStyle.CodeStyleManager;
11 | import com.intellij.psi.javadoc.PsiDocComment;
12 | import com.intellij.util.ThrowableRunnable;
13 | import org.apache.commons.lang3.StringUtils;
14 |
15 | /**
16 | * @author wangchao
17 | * @date 2019/08/25
18 | */
19 | public class WriterService {
20 | private static final Logger LOGGER = Logger.getInstance(WriterService.class);
21 |
22 | public void write(Project project, PsiElement psiElement, PsiDocComment comment) {
23 | try {
24 | WriteCommandAction.writeCommandAction(project).run(
25 | (ThrowableRunnable) () -> {
26 | if (psiElement.getContainingFile() == null) {
27 | return;
28 | }
29 |
30 | // 写入文档注释
31 | if (psiElement instanceof PsiJavaDocumentedElement) {
32 | PsiDocComment psiDocComment = ((PsiJavaDocumentedElement) psiElement).getDocComment();
33 | if (psiDocComment == null) {
34 | psiElement.getNode().addChild(comment.getNode(), psiElement.getFirstChild().getNode());
35 | } else {
36 | psiDocComment.replace(comment);
37 | }
38 | }
39 |
40 | // 格式化文档注释
41 | CodeStyleManager codeStyleManager = CodeStyleManager.getInstance(psiElement.getProject());
42 | PsiElement javadocElement = psiElement.getFirstChild();
43 | int startOffset = javadocElement.getTextOffset();
44 | int endOffset = javadocElement.getTextOffset() + javadocElement.getText().length();
45 | codeStyleManager.reformatText(psiElement.getContainingFile(), startOffset, endOffset + 1);
46 | });
47 | } catch (Throwable throwable) {
48 | LOGGER.error("写入错误", throwable);
49 | }
50 | }
51 |
52 | public void write(Project project, Editor editor, String text) {
53 | if (project == null || editor == null || StringUtils.isBlank(text)) {
54 | return;
55 | }
56 | try {
57 | WriteCommandAction.writeCommandAction(project).run(
58 | (ThrowableRunnable) () -> {
59 | int start = editor.getSelectionModel().getSelectionStart();
60 | EditorModificationUtil.insertStringAtCaret(editor, text);
61 | editor.getSelectionModel().setSelection(start, start + text.length());
62 | });
63 | } catch (Throwable throwable) {
64 | LOGGER.error("写入错误", throwable);
65 | }
66 | }
67 | }
68 |
--------------------------------------------------------------------------------
/src/main/java/com/liuzhihang/doc/view/ui/YApiSettingForm.java:
--------------------------------------------------------------------------------
1 | package com.liuzhihang.doc.view.ui;
2 |
3 | import com.intellij.openapi.options.ConfigurationException;
4 | import com.intellij.openapi.project.Project;
5 | import com.intellij.ui.IdeBorderFactory;
6 | import com.intellij.ui.components.JBTextField;
7 | import com.liuzhihang.doc.view.DocViewBundle;
8 | import com.liuzhihang.doc.view.config.YApiSettings;
9 | import com.liuzhihang.doc.view.notification.DocViewNotification;
10 |
11 | import javax.swing.*;
12 | import java.util.regex.Pattern;
13 |
14 | public class YApiSettingForm {
15 | private JPanel rootPanel;
16 |
17 | private JPanel yapiProjectPanel;
18 | private JBTextField urlTextField;
19 | private JBTextField projectIdTextField;
20 | private JBTextField tokenTextField;
21 |
22 |
23 | private final Project project;
24 |
25 | public YApiSettingForm(Project project) {
26 | this.project = project;
27 | yapiProjectPanel.setBorder(IdeBorderFactory.createTitledBorder(DocViewBundle.message("yapi.project.panel")));
28 | }
29 |
30 | public JPanel getRootPanel() {
31 | return rootPanel;
32 | }
33 |
34 |
35 | public boolean isModified() {
36 |
37 | YApiSettings settings = YApiSettings.getInstance(project);
38 |
39 | if (!urlTextField.getText().equals(settings.getUrl())) {
40 | return true;
41 | }
42 |
43 | String projectId = projectIdTextField.getText().trim();
44 |
45 |
46 | if (!Pattern.compile("^?[0-9]+").matcher(projectId).matches()) {
47 | return false;
48 | }
49 |
50 | if (Long.parseLong(projectId) != settings.getProjectId()) {
51 | return true;
52 | }
53 |
54 | if (!tokenTextField.getText().equals(settings.getToken())) {
55 | return true;
56 | }
57 |
58 | return false;
59 | }
60 |
61 | public void apply() throws ConfigurationException {
62 | try {
63 | YApiSettings settings = YApiSettings.getInstance(project);
64 | String urlTextFieldText = urlTextField.getText();
65 |
66 | if (urlTextFieldText.endsWith("/")) {
67 | settings.setUrl(urlTextFieldText.substring(0, urlTextFieldText.length() - 1));
68 | } else {
69 | settings.setUrl(urlTextFieldText);
70 | }
71 |
72 | String projectId = projectIdTextField.getText().trim();
73 | if (Pattern.compile("^?[0-9]+").matcher(projectId).matches()) {
74 | settings.setProjectId(Long.parseLong(projectId));
75 | } else {
76 | DocViewNotification.notifyError(project, DocViewBundle.message("notify.yapi.project.id"));
77 | }
78 |
79 | settings.setToken(tokenTextField.getText());
80 | } catch (NumberFormatException e) {
81 | throw new ConfigurationException(DocViewBundle.message("notify.yapi.project.id"));
82 | }
83 | }
84 |
85 | public void reset() {
86 | YApiSettings settings = YApiSettings.getInstance(project);
87 | urlTextField.setText(settings.getUrl());
88 | if (settings.getProjectId() != null) {
89 | projectIdTextField.setText(settings.getProjectId().toString());
90 | }
91 | tokenTextField.setText(settings.getToken());
92 | }
93 |
94 | }
95 |
--------------------------------------------------------------------------------
/src/main/java/com/liuzhihang/doc/view/ui/YuQueSettingForm.java:
--------------------------------------------------------------------------------
1 | package com.liuzhihang.doc.view.ui;
2 |
3 | import com.intellij.openapi.options.ConfigurationException;
4 | import com.intellij.openapi.project.Project;
5 | import com.intellij.ui.IdeBorderFactory;
6 | import com.intellij.ui.components.JBTextField;
7 | import com.liuzhihang.doc.view.DocViewBundle;
8 | import com.liuzhihang.doc.view.config.YuQueSettings;
9 |
10 | import javax.swing.*;
11 |
12 | /**
13 | * @author liuzhihang
14 | * @date 2022/4/3 11:25
15 | */
16 | public class YuQueSettingForm {
17 | private JPanel rootPanel;
18 | private JPanel yuQueProjectPanel;
19 | private JBTextField urlTextField;
20 | private JBTextField loginTextField;
21 | private JBTextField reposTextField;
22 | private JBTextField tokenTextField;
23 | private JBTextField apiUrlTextField;
24 |
25 |
26 | private final Project project;
27 |
28 | public YuQueSettingForm(Project project) {
29 | this.project = project;
30 | yuQueProjectPanel.setBorder(IdeBorderFactory.createTitledBorder(DocViewBundle.message("yapi.project.panel")));
31 | }
32 |
33 | public JPanel getRootPanel() {
34 | return rootPanel;
35 | }
36 |
37 |
38 | public boolean isModified() {
39 |
40 | YuQueSettings settings = YuQueSettings.getInstance(project);
41 |
42 | if (!urlTextField.getText().trim().equals(settings.getUrl())) {
43 | return true;
44 | }
45 | if (!apiUrlTextField.getText().trim().equals(settings.getApiUrl())) {
46 | return true;
47 | }
48 |
49 | if (!loginTextField.getText().trim().equals(settings.getLogin())) {
50 | return true;
51 | }
52 |
53 | if (!reposTextField.getText().trim().equals(settings.getRepos())) {
54 | return true;
55 | }
56 |
57 | if (!tokenTextField.getText().trim().equals(settings.getToken())) {
58 | return true;
59 | }
60 |
61 | return false;
62 | }
63 |
64 | public void apply() throws ConfigurationException {
65 | YuQueSettings settings = YuQueSettings.getInstance(project);
66 | String urlTextFieldText = urlTextField.getText().trim();
67 |
68 | if (urlTextFieldText.endsWith("/")) {
69 | settings.setUrl(urlTextFieldText.substring(0, urlTextFieldText.length() - 1));
70 | } else {
71 | settings.setUrl(urlTextFieldText);
72 | }
73 | String apiUrlTextFieldText = apiUrlTextField.getText().trim();
74 |
75 | if (apiUrlTextFieldText.endsWith("/")) {
76 | settings.setApiUrl(apiUrlTextFieldText.substring(0, apiUrlTextFieldText.length() - 1));
77 | } else {
78 | settings.setApiUrl(apiUrlTextFieldText);
79 | }
80 |
81 | settings.setLogin(loginTextField.getText().trim());
82 | settings.setRepos(reposTextField.getText().trim());
83 | settings.setToken(tokenTextField.getText().trim());
84 |
85 | }
86 |
87 | public void reset() {
88 | YuQueSettings settings = YuQueSettings.getInstance(project);
89 | urlTextField.setText(settings.getUrl());
90 | apiUrlTextField.setText(settings.getApiUrl());
91 | tokenTextField.setText(settings.getToken());
92 | loginTextField.setText(settings.getLogin());
93 | reposTextField.setText(settings.getRepos());
94 | }
95 | }
96 |
--------------------------------------------------------------------------------
/src/main/java/com/liuzhihang/doc/view/ui/TemplateSettingForm.form:
--------------------------------------------------------------------------------
1 |
2 |
69 |
--------------------------------------------------------------------------------
/src/main/java/com/liuzhihang/doc/view/service/impl/ShowDocServiceImpl.java:
--------------------------------------------------------------------------------
1 | package com.liuzhihang.doc.view.service.impl;
2 |
3 | import com.intellij.openapi.application.ApplicationManager;
4 | import com.intellij.openapi.components.Service;
5 | import com.intellij.openapi.options.ShowSettingsUtil;
6 | import com.intellij.openapi.project.Project;
7 | import com.liuzhihang.doc.view.DocViewBundle;
8 | import com.liuzhihang.doc.view.config.ShowDocSettings;
9 | import com.liuzhihang.doc.view.config.ShowDocSettingsConfigurable;
10 | import com.liuzhihang.doc.view.dto.DocView;
11 | import com.liuzhihang.doc.view.dto.DocViewData;
12 | import com.liuzhihang.doc.view.integration.ShowDocFacadeService;
13 | import com.liuzhihang.doc.view.integration.dto.ShowDocUpdateRequest;
14 | import com.liuzhihang.doc.view.integration.dto.ShowDocUpdateResponse;
15 | import com.liuzhihang.doc.view.integration.impl.ShowDocFacadeServiceImpl;
16 | import com.liuzhihang.doc.view.notification.DocViewNotification;
17 | import com.liuzhihang.doc.view.service.DocViewUploadService;
18 | import lombok.extern.slf4j.Slf4j;
19 | import org.apache.commons.lang3.StringUtils;
20 | import org.jetbrains.annotations.NotNull;
21 |
22 | /**
23 | * @author liuzhihang
24 | * @date 2021/7/27 12:00
25 | */
26 | @Slf4j
27 | @Service
28 | public final class ShowDocServiceImpl implements DocViewUploadService {
29 |
30 |
31 | @Override
32 | public boolean checkSettings(@NotNull Project project) {
33 | ShowDocSettings apiSettings = ShowDocSettings.getInstance(project);
34 |
35 | if (StringUtils.isBlank(apiSettings.getUrl())
36 | || StringUtils.isBlank(apiSettings.getApiKey())
37 | || StringUtils.isBlank(apiSettings.getApiToken())) {
38 | // 说明没有配置 ShowDoc 上传地址, 跳转到配置页面
39 | DocViewNotification.notifyError(project, DocViewBundle.message("notify.showdoc.info.settings"));
40 | ShowSettingsUtil.getInstance().showSettingsDialog(project, ShowDocSettingsConfigurable.class);
41 | return false;
42 | }
43 | return true;
44 | }
45 |
46 | @Override
47 | public void doUpload(@NotNull Project project, @NotNull DocView docView) {
48 |
49 | try {
50 | ShowDocSettings settings = ShowDocSettings.getInstance(project);
51 |
52 | ShowDocUpdateRequest request = new ShowDocUpdateRequest();
53 | request.setShowDocUrl(settings.getUrl());
54 | request.setApiKey(settings.getApiKey());
55 | request.setApiToken(settings.getApiToken());
56 | request.setCatName(docView.getDocTitle());
57 | request.setPageTitle(docView.getName());
58 | request.setPageContent(DocViewData.markdownText(project, docView));
59 |
60 | ShowDocFacadeService facadeService = ApplicationManager.getApplication().getService(ShowDocFacadeServiceImpl.class);
61 | ShowDocUpdateResponse response = facadeService.updateByApi(request);
62 |
63 | ShowDocUpdateResponse.DataInner data = response.getData();
64 |
65 | String showDocInterfaceUrl = settings.getUrl() + "/" + data.getItemId() + "/" + data.getPageId();
66 |
67 | DocViewNotification.uploadSuccess(project, "ShowDoc", showDocInterfaceUrl);
68 | } catch (Exception e) {
69 | DocViewNotification.notifyError(project, DocViewBundle.message("notify.showdoc.upload.error"));
70 | log.error("上传单个文档失败:{}", docView, e);
71 | }
72 | }
73 | }
74 |
--------------------------------------------------------------------------------
/src/main/java/com/liuzhihang/doc/view/service/impl/DubboDocViewServiceImpl.java:
--------------------------------------------------------------------------------
1 | package com.liuzhihang.doc.view.service.impl;
2 |
3 | import com.intellij.psi.PsiClass;
4 | import com.intellij.psi.PsiMethod;
5 | import com.intellij.psi.PsiType;
6 | import com.liuzhihang.doc.view.dto.DocView;
7 | import com.liuzhihang.doc.view.enums.ContentTypeEnum;
8 | import com.liuzhihang.doc.view.enums.FrameworkEnum;
9 | import com.liuzhihang.doc.view.service.DocViewService;
10 | import com.liuzhihang.doc.view.utils.DocViewUtils;
11 | import com.liuzhihang.doc.view.utils.DubboPsiUtils;
12 | import com.liuzhihang.doc.view.utils.ParamPsiUtils;
13 | import org.jetbrains.annotations.NotNull;
14 |
15 | import java.util.LinkedList;
16 | import java.util.List;
17 |
18 | /**
19 | * Dubbo 处理服务
20 | *
21 | * @author liuzhihang
22 | * @date 2020/11/16 18:28
23 | */
24 | public class DubboDocViewServiceImpl implements DocViewService {
25 |
26 |
27 | /**
28 | * 校验方法是否为符合条件
29 | *
30 | * @param targetMethod 当前方法
31 | * @return 是否
32 | */
33 | @Override
34 | public boolean checkMethod(@NotNull PsiMethod targetMethod) {
35 | return DubboPsiUtils.isDubboMethod(targetMethod);
36 | }
37 |
38 | /**
39 | * 创建类的文档
40 | *
41 | * 可能会存在重载方法,所以这里需要对重载进行处理
42 | *
43 | * @param psiClass 当前类
44 | * @return 类的所有接口文档
45 | */
46 | @Override
47 | public List buildClassDoc(@NotNull PsiClass psiClass) {
48 |
49 | List docViewList = new LinkedList<>();
50 |
51 | for (PsiMethod method : psiClass.getMethods()) {
52 | if (!DubboPsiUtils.isDubboMethod(method)) {
53 | continue;
54 | }
55 |
56 | DocView docView = buildClassMethodDoc(psiClass, method);
57 | docViewList.add(docView);
58 | }
59 |
60 | return docViewList;
61 |
62 | }
63 |
64 | /**
65 | * 构造当前类方法的文档
66 | *
67 | * @param psiClass 当前类
68 | * @param psiMethod 当前方法
69 | * @return
70 | */
71 | @NotNull
72 | @Override
73 | public DocView buildClassMethodDoc(@NotNull PsiClass psiClass, @NotNull PsiMethod psiMethod) {
74 | DocView docView = new DocView();
75 | docView.setPsiClass(psiClass);
76 | docView.setPsiMethod(psiMethod);
77 | docView.setDocTitle(DocViewUtils.getTitle(psiClass));
78 | docView.setName(DocViewUtils.getName(psiMethod));
79 | docView.setDesc(DocViewUtils.getMethodDesc(psiMethod));
80 | docView.setPath(psiClass.getName() + "#" + psiMethod.getName());
81 | docView.setMethod("Dubbo");
82 | // docView.setDomain();
83 | docView.setType(FrameworkEnum.DUBBO);
84 |
85 | // 有参数
86 | if (psiMethod.hasParameters()) {
87 | docView.setReqBody(DubboPsiUtils.buildBody(psiMethod));
88 | docView.setContentType(ContentTypeEnum.JSON);
89 | docView.setReqBodyExample(DubboPsiUtils.getReqBodyJson(psiMethod));
90 | }
91 |
92 | PsiType returnType = psiMethod.getReturnType();
93 | // 返回代码相同
94 | if (returnType != null && returnType.isValid() && !returnType.equalsToText("void")) {
95 | docView.setRespBody(ParamPsiUtils.buildRespBody(returnType));
96 | docView.setRespExample(ParamPsiUtils.getRespBodyJson(returnType));
97 | }
98 | return docView;
99 |
100 | }
101 | }
102 |
--------------------------------------------------------------------------------
/src/main/java/com/liuzhihang/doc/view/ui/window/ModuleNode.java:
--------------------------------------------------------------------------------
1 | package com.liuzhihang.doc.view.ui.window;
2 |
3 | import com.intellij.icons.AllIcons;
4 | import com.intellij.openapi.module.Module;
5 | import com.intellij.openapi.project.Project;
6 | import com.intellij.openapi.util.NlsSafe;
7 | import com.intellij.psi.PsiClass;
8 | import com.intellij.psi.search.GlobalSearchScope;
9 | import com.intellij.psi.search.searches.AllClassesSearch;
10 | import com.intellij.ui.treeStructure.SimpleNode;
11 | import com.liuzhihang.doc.view.config.Settings;
12 | import com.liuzhihang.doc.view.dto.DocView;
13 | import com.liuzhihang.doc.view.utils.DubboPsiUtils;
14 | import com.liuzhihang.doc.view.utils.FeignPsiUtil;
15 | import com.liuzhihang.doc.view.utils.SpringPsiUtils;
16 |
17 | import java.util.ArrayList;
18 | import java.util.Collection;
19 | import java.util.LinkedList;
20 | import java.util.List;
21 | import java.util.stream.Collectors;
22 |
23 | /**
24 | * @author liuzhihang
25 | * @date 2022/4/4 17:06
26 | */
27 | public class ModuleNode extends DocViewNode {
28 |
29 | private final List classNodes = new ArrayList<>();
30 | private final Module module;
31 |
32 | protected ModuleNode(SimpleNode aParent, Module module) {
33 | super(aParent);
34 | this.module = module;
35 |
36 | getTemplatePresentation().setIcon(AllIcons.Nodes.Module);
37 | getTemplatePresentation().setPresentableText(getName());
38 | updateNode(module.getProject());
39 | }
40 |
41 | public void updateNode(Project project) {
42 | cleanUpCache();
43 | classNodes.clear();
44 |
45 | List psiClasses = new LinkedList<>();
46 |
47 | if (Settings.getInstance(project).getIncludeNormalInterface()) {
48 | // 包含普通接口则扫描所有接口
49 | List interfaceList = AllClassesSearch.search(GlobalSearchScope.moduleScope(module), project).findAll()
50 | .stream()
51 | .filter(PsiClass::isInterface)
52 | .collect(Collectors.toList());
53 | psiClasses.addAll(interfaceList);
54 | } else {
55 | psiClasses.addAll(DubboPsiUtils.findDocViewFromModule(module));
56 | psiClasses.addAll(FeignPsiUtil.findDocViewFromModule(module));
57 | }
58 |
59 | psiClasses.addAll(SpringPsiUtils.findDocViewFromModule(module));
60 |
61 | for (PsiClass psiClass : psiClasses) {
62 | ClassNode classNode = new ClassNode(this, psiClass);
63 | classNodes.add(classNode);
64 | }
65 | update();
66 | }
67 |
68 | @Override
69 | public String docPath(Project project) {
70 |
71 | RootNode rootNode = (RootNode) getParent();
72 |
73 | return rootNode.docPath(project) + "/" + module.getName();
74 | }
75 |
76 | @Override
77 | public String httpPath(Project project) {
78 |
79 | RootNode rootNode = (RootNode) getParent();
80 |
81 | return rootNode.httpPath(project) + "/" + module.getName();
82 | }
83 |
84 | @Override
85 | protected SimpleNode[] buildChildren() {
86 | return classNodes.toArray(new SimpleNode[0]);
87 | }
88 |
89 | @Override
90 | public @NlsSafe String getName() {
91 | return module.getName();
92 | }
93 |
94 | @Override
95 | public List docViewList() {
96 | return classNodes.stream().map(ClassNode::docViewList).flatMap(Collection::stream).collect(Collectors.toList());
97 | }
98 | }
99 |
--------------------------------------------------------------------------------
/src/main/java/com/liuzhihang/doc/view/action/toolbar/window/WindowExportAction.java:
--------------------------------------------------------------------------------
1 | package com.liuzhihang.doc.view.action.toolbar.window;
2 |
3 | import com.intellij.openapi.actionSystem.AnAction;
4 | import com.intellij.openapi.actionSystem.AnActionEvent;
5 | import com.intellij.openapi.actionSystem.PlatformDataKeys;
6 | import com.intellij.openapi.application.ApplicationManager;
7 | import com.intellij.openapi.fileChooser.FileChooser;
8 | import com.intellij.openapi.fileChooser.FileChooserDescriptor;
9 | import com.intellij.openapi.fileChooser.FileChooserDescriptorFactory;
10 | import com.intellij.openapi.progress.ProgressIndicator;
11 | import com.intellij.openapi.progress.ProgressManager;
12 | import com.intellij.openapi.progress.Task;
13 | import com.intellij.openapi.project.Project;
14 | import com.intellij.openapi.util.io.FileUtil;
15 | import com.intellij.openapi.vfs.VirtualFile;
16 | import com.liuzhihang.doc.view.DocViewBundle;
17 | import com.liuzhihang.doc.view.data.DocViewDataKeys;
18 | import com.liuzhihang.doc.view.dto.DocView;
19 | import com.liuzhihang.doc.view.dto.DocViewData;
20 | import com.liuzhihang.doc.view.notification.DocViewNotification;
21 | import com.liuzhihang.doc.view.ui.window.RootNode;
22 | import com.liuzhihang.doc.view.utils.DialogUtil;
23 | import org.jetbrains.annotations.NotNull;
24 |
25 | import javax.swing.*;
26 | import java.io.File;
27 |
28 | /**
29 | * @author liuzhihang
30 | * @date 2021/10/23 19:55
31 | */
32 | public class WindowExportAction extends AnAction {
33 |
34 | @Override
35 | public void actionPerformed(@NotNull AnActionEvent e) {
36 |
37 | // 获取当前project对象
38 | Project project = e.getData(PlatformDataKeys.PROJECT);
39 | JComponent toolbar = e.getData(DocViewDataKeys.WINDOW_TOOLBAR);
40 | RootNode rootNode = e.getData(DocViewDataKeys.WINDOW_ROOT_NODE);
41 |
42 | if (project == null || toolbar == null || rootNode == null || rootNode.getChildCount() == 0) {
43 | DocViewNotification.notifyError(project, DocViewBundle.message("notify.window.export.empty"));
44 | return;
45 | }
46 | // 选择路径
47 | FileChooserDescriptor fileChooserDescriptor = FileChooserDescriptorFactory.createSingleFolderDescriptor();
48 | fileChooserDescriptor.setForcedToUseIdeaFileChooser(true);
49 | VirtualFile chooser = FileChooser.chooseFile(fileChooserDescriptor, project, null);
50 | if (chooser == null) {
51 | return;
52 | }
53 | String path = chooser.getPath();
54 |
55 | // 导出到一个文件中
56 | File file = new File(path + "/DocView.md");
57 |
58 | // 文件已存在,选择是否覆盖导出。
59 | if (file.exists() && !DialogUtil.confirm(
60 | DocViewBundle.message("notify.export.file.exists"),
61 | DocViewBundle.message("notify.export.file.cover"))) {
62 | return;
63 | }
64 | ProgressManager.getInstance().run(new Task.Backgroundable(project, "Doc View export", true) {
65 | @Override
66 | public void run(@NotNull ProgressIndicator progressIndicator) {
67 |
68 | ApplicationManager.getApplication().executeOnPooledThread(() -> ApplicationManager.getApplication().runReadAction(() -> {
69 |
70 | for (DocView docView : rootNode.docViewList()) {
71 | try {
72 | FileUtil.writeToFile(file, DocViewData.markdownText(project, docView), true);
73 | } catch (Exception ignored) {
74 | }
75 | }
76 |
77 | }));
78 |
79 |
80 | }
81 | });
82 | }
83 | }
84 |
--------------------------------------------------------------------------------