├── .idea ├── compiler.xml ├── encodings.xml ├── inspectionProfiles │ └── Project_Default.xml ├── libraries │ ├── Maven__ch_qos_logback_logback_classic_1_2_3.xml │ ├── Maven__ch_qos_logback_logback_core_1_2_3.xml │ ├── Maven__com_fasterxml_classmate_1_5_1.xml │ ├── Maven__com_fasterxml_jackson_core_jackson_annotations_2_10_2.xml │ ├── Maven__com_fasterxml_jackson_core_jackson_core_2_10_2.xml │ ├── Maven__com_fasterxml_jackson_core_jackson_databind_2_10_2.xml │ ├── Maven__com_fasterxml_jackson_datatype_jackson_datatype_jdk8_2_10_2.xml │ ├── Maven__com_fasterxml_jackson_datatype_jackson_datatype_jsr310_2_10_2.xml │ ├── Maven__com_fasterxml_jackson_module_jackson_module_parameter_names_2_10_2.xml │ ├── Maven__com_jayway_jsonpath_json_path_2_4_0.xml │ ├── Maven__com_vaadin_external_google_android_json_0_0_20131108_vaadin1.xml │ ├── Maven__jakarta_activation_jakarta_activation_api_1_2_1.xml │ ├── Maven__jakarta_annotation_jakarta_annotation_api_1_3_5.xml │ ├── Maven__jakarta_validation_jakarta_validation_api_2_0_2.xml │ ├── Maven__jakarta_xml_bind_jakarta_xml_bind_api_2_3_2.xml │ ├── Maven__net_bytebuddy_byte_buddy_1_10_6.xml │ ├── Maven__net_bytebuddy_byte_buddy_agent_1_10_6.xml │ ├── Maven__net_minidev_accessors_smart_1_2.xml │ ├── Maven__net_minidev_json_smart_2_3.xml │ ├── Maven__org_apache_logging_log4j_log4j_api_2_12_1.xml │ ├── Maven__org_apache_logging_log4j_log4j_to_slf4j_2_12_1.xml │ ├── Maven__org_apache_tomcat_embed_tomcat_embed_core_9_0_30.xml │ ├── Maven__org_apache_tomcat_embed_tomcat_embed_el_9_0_30.xml │ ├── Maven__org_apache_tomcat_embed_tomcat_embed_websocket_9_0_30.xml │ ├── Maven__org_apiguardian_apiguardian_api_1_1_0.xml │ ├── Maven__org_assertj_assertj_core_3_13_2.xml │ ├── Maven__org_attoparser_attoparser_2_0_5_RELEASE.xml │ ├── Maven__org_hamcrest_hamcrest_2_1.xml │ ├── Maven__org_hibernate_validator_hibernate_validator_6_0_18_Final.xml │ ├── Maven__org_jboss_logging_jboss_logging_3_4_1_Final.xml │ ├── Maven__org_junit_jupiter_junit_jupiter_5_5_2.xml │ ├── Maven__org_junit_jupiter_junit_jupiter_api_5_5_2.xml │ ├── Maven__org_junit_jupiter_junit_jupiter_engine_5_5_2.xml │ ├── Maven__org_junit_jupiter_junit_jupiter_params_5_5_2.xml │ ├── Maven__org_junit_platform_junit_platform_commons_1_5_2.xml │ ├── Maven__org_junit_platform_junit_platform_engine_1_5_2.xml │ ├── Maven__org_mockito_mockito_core_3_1_0.xml │ ├── Maven__org_mockito_mockito_junit_jupiter_3_1_0.xml │ ├── Maven__org_objenesis_objenesis_2_6.xml │ ├── Maven__org_opentest4j_opentest4j_1_2_0.xml │ ├── Maven__org_ow2_asm_asm_5_0_4.xml │ ├── Maven__org_projectlombok_lombok_1_18_10.xml │ ├── Maven__org_skyscreamer_jsonassert_1_5_0.xml │ ├── Maven__org_slf4j_jul_to_slf4j_1_7_30.xml │ ├── Maven__org_slf4j_slf4j_api_1_7_30.xml │ ├── Maven__org_springframework_boot_spring_boot_2_2_4_RELEASE.xml │ ├── Maven__org_springframework_boot_spring_boot_autoconfigure_2_2_4_RELEASE.xml │ ├── Maven__org_springframework_boot_spring_boot_starter_2_2_4_RELEASE.xml │ ├── Maven__org_springframework_boot_spring_boot_starter_json_2_2_4_RELEASE.xml │ ├── Maven__org_springframework_boot_spring_boot_starter_logging_2_2_4_RELEASE.xml │ ├── Maven__org_springframework_boot_spring_boot_starter_test_2_2_4_RELEASE.xml │ ├── Maven__org_springframework_boot_spring_boot_starter_thymeleaf_2_2_4_RELEASE.xml │ ├── Maven__org_springframework_boot_spring_boot_starter_tomcat_2_2_4_RELEASE.xml │ ├── Maven__org_springframework_boot_spring_boot_starter_validation_2_2_4_RELEASE.xml │ ├── Maven__org_springframework_boot_spring_boot_starter_web_2_2_4_RELEASE.xml │ ├── Maven__org_springframework_boot_spring_boot_test_2_2_4_RELEASE.xml │ ├── Maven__org_springframework_boot_spring_boot_test_autoconfigure_2_2_4_RELEASE.xml │ ├── Maven__org_springframework_spring_aop_5_2_3_RELEASE.xml │ ├── Maven__org_springframework_spring_beans_5_2_3_RELEASE.xml │ ├── Maven__org_springframework_spring_context_5_2_3_RELEASE.xml │ ├── Maven__org_springframework_spring_core_5_2_3_RELEASE.xml │ ├── Maven__org_springframework_spring_expression_5_2_3_RELEASE.xml │ ├── Maven__org_springframework_spring_jcl_5_2_3_RELEASE.xml │ ├── Maven__org_springframework_spring_test_5_2_3_RELEASE.xml │ ├── Maven__org_springframework_spring_web_5_2_3_RELEASE.xml │ ├── Maven__org_springframework_spring_webmvc_5_2_3_RELEASE.xml │ ├── Maven__org_thymeleaf_extras_thymeleaf_extras_java8time_3_0_4_RELEASE.xml │ ├── Maven__org_thymeleaf_thymeleaf_3_0_11_RELEASE.xml │ ├── Maven__org_thymeleaf_thymeleaf_spring5_3_0_11_RELEASE.xml │ ├── Maven__org_unbescape_unbescape_1_1_6_RELEASE.xml │ ├── Maven__org_xmlunit_xmlunit_core_2_6_3.xml │ └── Maven__org_yaml_snakeyaml_1_25.xml ├── misc.xml ├── modules.xml ├── uiDesigner.xml └── workspace.xml ├── README.md ├── code-editor.iml ├── pom.xml └── src ├── main ├── java │ └── com │ │ └── leisurexi │ │ └── codeeditor │ │ ├── CodeEditorApplication.java │ │ ├── api │ │ ├── BaseResponse.java │ │ └── ResultCode.java │ │ ├── classloader │ │ └── FileClassLoader.java │ │ ├── controller │ │ └── IndexController.java │ │ ├── dto │ │ ├── ExecuteCodeResponse.java │ │ └── ExecuteResults.java │ │ ├── exception │ │ └── GlobalExceptionTranslator.java │ │ ├── service │ │ └── IndexService.java │ │ └── util │ │ └── ResourceUtil.java └── resources │ ├── application.properties │ ├── classes │ └── a │ ├── static │ ├── css │ │ ├── bootstrap.css │ │ ├── codemirror.css │ │ └── style.css │ ├── js │ │ ├── bootstrap.js │ │ ├── codemirror.js │ │ └── jquery-3.4.1.min.js │ └── model │ │ └── clike.js │ └── templates │ └── index.html └── test └── java └── com └── leisurexi └── codeeditor └── CodeEditorApplicationTests.java /.idea/compiler.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 20 | 21 | -------------------------------------------------------------------------------- /.idea/encodings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /.idea/inspectionProfiles/Project_Default.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 36 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__ch_qos_logback_logback_classic_1_2_3.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__ch_qos_logback_logback_core_1_2_3.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__com_fasterxml_classmate_1_5_1.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__com_fasterxml_jackson_core_jackson_annotations_2_10_2.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__com_fasterxml_jackson_core_jackson_core_2_10_2.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__com_fasterxml_jackson_core_jackson_databind_2_10_2.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__com_fasterxml_jackson_datatype_jackson_datatype_jdk8_2_10_2.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__com_fasterxml_jackson_datatype_jackson_datatype_jsr310_2_10_2.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__com_fasterxml_jackson_module_jackson_module_parameter_names_2_10_2.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__com_jayway_jsonpath_json_path_2_4_0.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__com_vaadin_external_google_android_json_0_0_20131108_vaadin1.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__jakarta_activation_jakarta_activation_api_1_2_1.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__jakarta_annotation_jakarta_annotation_api_1_3_5.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__jakarta_validation_jakarta_validation_api_2_0_2.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__jakarta_xml_bind_jakarta_xml_bind_api_2_3_2.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__net_bytebuddy_byte_buddy_1_10_6.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__net_bytebuddy_byte_buddy_agent_1_10_6.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__net_minidev_accessors_smart_1_2.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__net_minidev_json_smart_2_3.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__org_apache_logging_log4j_log4j_api_2_12_1.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__org_apache_logging_log4j_log4j_to_slf4j_2_12_1.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__org_apache_tomcat_embed_tomcat_embed_core_9_0_30.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__org_apache_tomcat_embed_tomcat_embed_el_9_0_30.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__org_apache_tomcat_embed_tomcat_embed_websocket_9_0_30.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__org_apiguardian_apiguardian_api_1_1_0.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__org_assertj_assertj_core_3_13_2.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__org_attoparser_attoparser_2_0_5_RELEASE.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__org_hamcrest_hamcrest_2_1.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__org_hibernate_validator_hibernate_validator_6_0_18_Final.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__org_jboss_logging_jboss_logging_3_4_1_Final.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__org_junit_jupiter_junit_jupiter_5_5_2.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__org_junit_jupiter_junit_jupiter_api_5_5_2.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__org_junit_jupiter_junit_jupiter_engine_5_5_2.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__org_junit_jupiter_junit_jupiter_params_5_5_2.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__org_junit_platform_junit_platform_commons_1_5_2.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__org_junit_platform_junit_platform_engine_1_5_2.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__org_mockito_mockito_core_3_1_0.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__org_mockito_mockito_junit_jupiter_3_1_0.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__org_objenesis_objenesis_2_6.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__org_opentest4j_opentest4j_1_2_0.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__org_ow2_asm_asm_5_0_4.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__org_projectlombok_lombok_1_18_10.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__org_skyscreamer_jsonassert_1_5_0.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__org_slf4j_jul_to_slf4j_1_7_30.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__org_slf4j_slf4j_api_1_7_30.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__org_springframework_boot_spring_boot_2_2_4_RELEASE.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__org_springframework_boot_spring_boot_autoconfigure_2_2_4_RELEASE.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__org_springframework_boot_spring_boot_starter_2_2_4_RELEASE.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__org_springframework_boot_spring_boot_starter_json_2_2_4_RELEASE.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__org_springframework_boot_spring_boot_starter_logging_2_2_4_RELEASE.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__org_springframework_boot_spring_boot_starter_test_2_2_4_RELEASE.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__org_springframework_boot_spring_boot_starter_thymeleaf_2_2_4_RELEASE.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__org_springframework_boot_spring_boot_starter_tomcat_2_2_4_RELEASE.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__org_springframework_boot_spring_boot_starter_validation_2_2_4_RELEASE.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__org_springframework_boot_spring_boot_starter_web_2_2_4_RELEASE.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__org_springframework_boot_spring_boot_test_2_2_4_RELEASE.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__org_springframework_boot_spring_boot_test_autoconfigure_2_2_4_RELEASE.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__org_springframework_spring_aop_5_2_3_RELEASE.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__org_springframework_spring_beans_5_2_3_RELEASE.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__org_springframework_spring_context_5_2_3_RELEASE.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__org_springframework_spring_core_5_2_3_RELEASE.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__org_springframework_spring_expression_5_2_3_RELEASE.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__org_springframework_spring_jcl_5_2_3_RELEASE.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__org_springframework_spring_test_5_2_3_RELEASE.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__org_springframework_spring_web_5_2_3_RELEASE.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__org_springframework_spring_webmvc_5_2_3_RELEASE.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__org_thymeleaf_extras_thymeleaf_extras_java8time_3_0_4_RELEASE.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__org_thymeleaf_thymeleaf_3_0_11_RELEASE.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__org_thymeleaf_thymeleaf_spring5_3_0_11_RELEASE.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__org_unbescape_unbescape_1_1_6_RELEASE.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__org_xmlunit_xmlunit_core_2_6_3.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/libraries/Maven__org_yaml_snakeyaml_1_25.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/modules.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /.idea/uiDesigner.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | -------------------------------------------------------------------------------- /.idea/workspace.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 10 | 11 | 18 | 19 | 20 | 21 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 69 | 70 | 71 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 1580557665980 80 | 86 | 87 | 88 | 89 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # 前言 2 | 模仿 `leetcode` 的一个在线代码编辑器,可以在线运行查看结果。 3 | # 主要功能实现 4 | 通过把字符串代码保存在 `.java` 文件中,然后通过 `JavaCompiler` 5 | 去动态编译生成 `.class` 文件,然后通过自定义类加载器 `FileClassLoader` 6 | 去加载生成的类,最后通过反射调用 `main` 方法拦截 **控制台输出信息** 返回给前段页面。 7 | 可以使用以下包中的 `api` : 8 | * java.io.* 9 | * java.lang.* 10 | * java.math.* 11 | * java.net.* 12 | * java.nio.* 13 | * java.text.* 14 | * java.time.* 15 | * java.util.* 16 | # 运行结果展示 17 | ## 成功结果展示 18 | ![FCF15D00-84D1-4095-A66D-E9ED4197AE5A.png](http://ww1.sinaimg.cn/large/006Vpl27ly1gbi601k02pj31k018w41r.jpg) 19 | 20 | ## 失败结果展示 21 | ![2462E104-D47E-4833-A582-8C4F5FD84BC3.png](http://ww1.sinaimg.cn/large/006Vpl27ly1gbi618kxs6j31i21c6n0w.jpg) -------------------------------------------------------------------------------- /code-editor.iml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 4.0.0 5 | 6 | org.springframework.boot 7 | spring-boot-starter-parent 8 | 2.2.4.RELEASE 9 | 10 | 11 | com.leisurexi 12 | codeeditor 13 | 0.0.1 14 | code-editor 15 | 一个在线的Java代码编辑器,可以在线运行。 16 | 17 | 18 | 1.8 19 | 20 | 21 | 22 | 23 | org.springframework.boot 24 | spring-boot-starter-thymeleaf 25 | 26 | 27 | org.springframework.boot 28 | spring-boot-starter-web 29 | 30 | 31 | 32 | org.projectlombok 33 | lombok 34 | true 35 | 36 | 37 | org.springframework.boot 38 | spring-boot-starter-test 39 | test 40 | 41 | 42 | org.junit.vintage 43 | junit-vintage-engine 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | org.springframework.boot 53 | spring-boot-maven-plugin 54 | 55 | 56 | 57 | 58 | 59 | -------------------------------------------------------------------------------- /src/main/java/com/leisurexi/codeeditor/CodeEditorApplication.java: -------------------------------------------------------------------------------- 1 | package com.leisurexi.codeeditor; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | 6 | @SpringBootApplication 7 | public class CodeEditorApplication { 8 | 9 | public static void main(String[] args) { 10 | SpringApplication.run(CodeEditorApplication.class, args); 11 | } 12 | 13 | } 14 | -------------------------------------------------------------------------------- /src/main/java/com/leisurexi/codeeditor/api/BaseResponse.java: -------------------------------------------------------------------------------- 1 | package com.leisurexi.codeeditor.api; 2 | 3 | import lombok.AllArgsConstructor; 4 | import lombok.Builder; 5 | import lombok.Data; 6 | 7 | @Data 8 | @AllArgsConstructor 9 | @Builder 10 | public class BaseResponse { 11 | 12 | private int code; 13 | private String message; 14 | 15 | public BaseResponse() { 16 | this.code = ResultCode.SUCCESS.code; 17 | this.message = ResultCode.SUCCESS.msg; 18 | } 19 | 20 | public BaseResponse(ResultCode resultCode) { 21 | this.code = resultCode.code; 22 | this.message = resultCode.msg; 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/main/java/com/leisurexi/codeeditor/api/ResultCode.java: -------------------------------------------------------------------------------- 1 | package com.leisurexi.codeeditor.api; 2 | 3 | import lombok.AllArgsConstructor; 4 | import lombok.Getter; 5 | 6 | import javax.servlet.http.HttpServletResponse; 7 | 8 | @Getter 9 | @AllArgsConstructor 10 | public enum ResultCode { 11 | SUCCESS(HttpServletResponse.SC_OK, "Operation is Successful"), 12 | 13 | FAILURE(HttpServletResponse.SC_BAD_REQUEST, "Biz Exception"), 14 | 15 | UN_AUTHORIZED(HttpServletResponse.SC_UNAUTHORIZED, "Request Unauthorized"), 16 | 17 | NOT_FOUND(HttpServletResponse.SC_NOT_FOUND, "404 Not Found"), 18 | 19 | MSG_NOT_READABLE(HttpServletResponse.SC_BAD_REQUEST, "Message Can't be Read"), 20 | 21 | METHOD_NOT_SUPPORTED(HttpServletResponse.SC_METHOD_NOT_ALLOWED, "Method Not Supported"), 22 | 23 | MEDIA_TYPE_NOT_SUPPORTED(HttpServletResponse.SC_UNSUPPORTED_MEDIA_TYPE, "Media Type Not Supported"), 24 | 25 | REQ_REJECT(HttpServletResponse.SC_FORBIDDEN, "Request Rejected"), 26 | 27 | INTERNAL_SERVER_ERROR(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, "Internal Server Error"), 28 | 29 | PARAM_MISS(HttpServletResponse.SC_BAD_REQUEST, "Missing Required Parameter"), 30 | 31 | PARAM_TYPE_ERROR(HttpServletResponse.SC_BAD_REQUEST, "Parameter Type Mismatch"), 32 | 33 | PARAM_BIND_ERROR(HttpServletResponse.SC_BAD_REQUEST, "Parameter Binding Error"), 34 | 35 | PARAM_VALID_ERROR(HttpServletResponse.SC_BAD_REQUEST, "Parameter Validation Error"); 36 | 37 | final int code; 38 | 39 | final String msg; 40 | } 41 | -------------------------------------------------------------------------------- /src/main/java/com/leisurexi/codeeditor/classloader/FileClassLoader.java: -------------------------------------------------------------------------------- 1 | package com.leisurexi.codeeditor.classloader; 2 | 3 | import java.io.FileInputStream; 4 | 5 | /** 6 | * @author: leisurexi 7 | * @date: 2020-02-02 10:35 上午 8 | * @description: 自定义类加载器,通过读取 class 文件去加载类 9 | * @since JDK 1.8 10 | */ 11 | public class FileClassLoader extends ClassLoader { 12 | 13 | /** 14 | * 根基文件地址加载类 15 | * 16 | * @param name class 文件的绝对地址 17 | * @return 18 | * @throws ClassNotFoundException 19 | */ 20 | @Override 21 | protected Class findClass(String name) throws ClassNotFoundException { 22 | try (FileInputStream inputStream = new FileInputStream(name)) { 23 | if (inputStream == null) { 24 | return super.findClass(name); 25 | } 26 | byte[] bytes = new byte[inputStream.available()]; 27 | inputStream.read(bytes); 28 | return defineClass(null, bytes, 0, bytes.length); 29 | } catch (Exception e) { 30 | throw new ClassNotFoundException(name); 31 | } 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/main/java/com/leisurexi/codeeditor/controller/IndexController.java: -------------------------------------------------------------------------------- 1 | package com.leisurexi.codeeditor.controller; 2 | 3 | import com.leisurexi.codeeditor.api.BaseResponse; 4 | import com.leisurexi.codeeditor.dto.ExecuteCodeResponse; 5 | import com.leisurexi.codeeditor.dto.ExecuteResults; 6 | import com.leisurexi.codeeditor.service.IndexService; 7 | import org.springframework.validation.annotation.Validated; 8 | import org.springframework.web.bind.annotation.PostMapping; 9 | import org.springframework.web.bind.annotation.RestController; 10 | 11 | import javax.annotation.Resource; 12 | import javax.validation.constraints.NotBlank; 13 | 14 | /** 15 | * @author: leisurexi 16 | * @date: 2020-02-01 9:33 下午 17 | * @description: 18 | * @since JDK 1.8 19 | */ 20 | @RestController 21 | @Validated 22 | public class IndexController { 23 | 24 | @Resource 25 | private IndexService indexService; 26 | 27 | @PostMapping("execute_code") 28 | public BaseResponse executeCode(@NotBlank(message = "请输入代码") String code) throws Exception { 29 | ExecuteResults executeResults = indexService.executeCode(code); 30 | return new ExecuteCodeResponse(executeResults); 31 | } 32 | 33 | } 34 | -------------------------------------------------------------------------------- /src/main/java/com/leisurexi/codeeditor/dto/ExecuteCodeResponse.java: -------------------------------------------------------------------------------- 1 | package com.leisurexi.codeeditor.dto; 2 | 3 | import com.leisurexi.codeeditor.api.BaseResponse; 4 | import lombok.*; 5 | 6 | /** 7 | * @author: leisurexi 8 | * @date: 2020-02-01 10:12 下午 9 | * @description: 10 | * @since JDK 1.8 11 | */ 12 | @Data 13 | @NoArgsConstructor 14 | @AllArgsConstructor 15 | @ToString(callSuper = true) 16 | @EqualsAndHashCode(callSuper = true) 17 | public class ExecuteCodeResponse extends BaseResponse { 18 | 19 | private ExecuteResults results; 20 | 21 | } 22 | -------------------------------------------------------------------------------- /src/main/java/com/leisurexi/codeeditor/dto/ExecuteResults.java: -------------------------------------------------------------------------------- 1 | package com.leisurexi.codeeditor.dto; 2 | 3 | import lombok.AllArgsConstructor; 4 | import lombok.Builder; 5 | import lombok.Data; 6 | import lombok.NoArgsConstructor; 7 | 8 | import java.util.List; 9 | 10 | /** 11 | * @author: leisurexi 12 | * @date: 2020-02-02 3:48 下午 13 | * @description: 14 | * @since JDK 1.8 15 | */ 16 | @Data 17 | @NoArgsConstructor 18 | @AllArgsConstructor 19 | @Builder 20 | public class ExecuteResults { 21 | 22 | /** 23 | * 编译是否成功 24 | */ 25 | private boolean compiled; 26 | 27 | /** 28 | * 编译失败此字段值为错误信息 29 | */ 30 | private List errorMessage; 31 | 32 | /** 33 | * 运行输出信息 34 | */ 35 | private String stdout; 36 | 37 | } 38 | -------------------------------------------------------------------------------- /src/main/java/com/leisurexi/codeeditor/exception/GlobalExceptionTranslator.java: -------------------------------------------------------------------------------- 1 | package com.leisurexi.codeeditor.exception; 2 | 3 | import com.leisurexi.codeeditor.api.BaseResponse; 4 | import com.leisurexi.codeeditor.api.ResultCode; 5 | import lombok.extern.slf4j.Slf4j; 6 | import org.springframework.web.bind.annotation.ExceptionHandler; 7 | import org.springframework.web.bind.annotation.RestControllerAdvice; 8 | 9 | import javax.validation.ConstraintViolationException; 10 | 11 | @RestControllerAdvice 12 | @Slf4j 13 | public class GlobalExceptionTranslator { 14 | 15 | @ExceptionHandler(ConstraintViolationException.class) 16 | public BaseResponse handleError(ConstraintViolationException e) { 17 | log.error("参数错误: {}", e.getLocalizedMessage()); 18 | return BaseResponse 19 | .builder() 20 | .code(ResultCode.PARAM_BIND_ERROR.getCode()) 21 | .message(e.getMessage()) 22 | .build(); 23 | } 24 | 25 | @ExceptionHandler(Throwable.class) 26 | public BaseResponse handleError(Throwable e) { 27 | e.printStackTrace(); 28 | log.error(e.toString()); 29 | return BaseResponse 30 | .builder() 31 | .code(ResultCode.INTERNAL_SERVER_ERROR.getCode()) 32 | .message(e.toString()) 33 | .build(); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/main/java/com/leisurexi/codeeditor/service/IndexService.java: -------------------------------------------------------------------------------- 1 | package com.leisurexi.codeeditor.service; 2 | 3 | import com.leisurexi.codeeditor.dto.ExecuteResults; 4 | import com.leisurexi.codeeditor.classloader.FileClassLoader; 5 | import com.leisurexi.codeeditor.util.ResourceUtil; 6 | import lombok.extern.slf4j.Slf4j; 7 | import org.springframework.stereotype.Service; 8 | 9 | import javax.tools.*; 10 | import java.io.*; 11 | import java.lang.reflect.Method; 12 | import java.util.ArrayList; 13 | import java.util.Collections; 14 | import java.util.List; 15 | 16 | /** 17 | * @author: leisurexi 18 | * @date: 2020-02-01 9:44 下午 19 | * @description: 20 | * @since JDK 1.8 21 | */ 22 | @Service 23 | @Slf4j 24 | public class IndexService { 25 | 26 | /** 27 | * 执行代码,返回执行结果 28 | * 29 | * @param code 代码字符串 30 | * @return 执行结果 31 | */ 32 | public ExecuteResults executeCode(String code) throws Exception { 33 | String stdout = null; 34 | code = "import java.io.*;\n" + 35 | "import java.lang.*;\n" + 36 | "import java.math.*;\n" + 37 | "import java.net.*;\n" + 38 | "import java.nio.*;\n" + 39 | "import java.text.*;\n" + 40 | "import java.time.*;\n" + 41 | "import java.util.*;\n" + code; 42 | String filePath = ResourceUtil.getUrl("classes") + "/Test.java"; 43 | List errorMessage = compilerJavaCode(filePath, code); 44 | //代表编译成功 45 | if (errorMessage.isEmpty()) { 46 | Class clazz = new FileClassLoader().loadClass(filePath.replace(".java", ".class")); 47 | if (clazz != null) { 48 | //给输出流加锁,防止多线程情况下的并发问题 49 | synchronized (System.out) { 50 | //原先的输出流 51 | PrintStream oldStream = System.out; 52 | //创建获取控制台信息的输出流 53 | ByteArrayOutputStream byteStream = new ByteArrayOutputStream(1024); 54 | PrintStream printStream = new PrintStream(byteStream); 55 | //截取控制台输出信息 56 | System.setOut(printStream); 57 | Method method = clazz.getMethod("main", new Class[]{String[].class}); 58 | method.invoke(null, new String[]{null}); 59 | //将截取的信息转换成字符串 60 | stdout = byteStream.toString(); 61 | //截取完毕,将输出信息返回给控制台 62 | System.setOut(oldStream); 63 | } 64 | } 65 | } 66 | 67 | return ExecuteResults.builder() 68 | .compiled(errorMessage.size() == 0) 69 | .errorMessage(errorMessage) 70 | .stdout(stdout == null ? "" : stdout) 71 | .build(); 72 | } 73 | 74 | /** 75 | * 保存代码字符串为.java文件,然后通过JavaCompiler编译为.class文件 76 | * 77 | * @param filePath .java文件地址 78 | * @param code 代码 79 | * @return 编译错误的信息,编译成功长度为0 80 | * @throws Exception 81 | */ 82 | private List compilerJavaCode(String filePath, String code) throws Exception { 83 | File file = new File(filePath); 84 | try (FileOutputStream outputStream = new FileOutputStream(file)) { 85 | byte[] bytes = code.getBytes(); 86 | outputStream.write(bytes); 87 | outputStream.flush(); 88 | // 使用JavaCompiler编译java文件 89 | JavaCompiler javaCompiler = ToolProvider.getSystemJavaCompiler(); 90 | // 建立DiagnosticCollector对象 91 | DiagnosticCollector diagnosticCollectors = new DiagnosticCollector<>(); 92 | StandardJavaFileManager fileManager = javaCompiler.getStandardFileManager(diagnosticCollectors, null, null); 93 | //建立用于保存被编译文件名的对象 94 | //每个文件被保存在一个继承JavaFileObject的类中 95 | Iterable fileObjects = fileManager.getJavaFileObjects(filePath); 96 | JavaCompiler.CompilationTask task = javaCompiler.getTask(null, fileManager, diagnosticCollectors, null, null, fileObjects); 97 | Boolean call = task.call(); 98 | fileManager.close(); 99 | 100 | if (call) { 101 | return Collections.emptyList(); 102 | } 103 | List errorMessage = new ArrayList<>(); 104 | for (Diagnostic diagnostic : diagnosticCollectors.getDiagnostics()) { 105 | String message = String.format("Line %s: error: %s", diagnostic.getLineNumber(), diagnostic.getMessage(null)); 106 | errorMessage.add(message); 107 | } 108 | errorMessage.add(errorMessage.size() + " errors"); 109 | return errorMessage; 110 | } catch (Exception e) { 111 | throw e; 112 | } 113 | } 114 | 115 | } 116 | -------------------------------------------------------------------------------- /src/main/java/com/leisurexi/codeeditor/util/ResourceUtil.java: -------------------------------------------------------------------------------- 1 | package com.leisurexi.codeeditor.util; 2 | 3 | import org.springframework.util.ResourceUtils; 4 | 5 | import java.io.FileNotFoundException; 6 | 7 | /** 8 | * @author: leisurexi 9 | * @date: 2020-02-02 10:11 上午 10 | * @description: 11 | * @since JDK 1.8 12 | */ 13 | public class ResourceUtil { 14 | 15 | /** 16 | * 获取 resources 文件夹下的绝对路径 17 | * 18 | * @param dirName 子文件夹名称 19 | * @return 20 | */ 21 | public static String getUrl(String dirName) { 22 | String path = null; 23 | try { 24 | path = ResourceUtils.getURL("classpath:" + dirName).getPath(); 25 | } catch (FileNotFoundException e) { 26 | e.printStackTrace(); 27 | } 28 | return path; 29 | } 30 | 31 | } 32 | -------------------------------------------------------------------------------- /src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | #视图层控制 2 | spring.mvc.view.prefix=classpath:/templates/** 3 | spring.mvc.view.suffix=.html 4 | spring.mvc.static-path-pattern=/static/** 5 | -------------------------------------------------------------------------------- /src/main/resources/classes/a: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/leisurexi/code-editor/46e652d890fa0d51b9daf2c047ea9cf2a12671af/src/main/resources/classes/a -------------------------------------------------------------------------------- /src/main/resources/static/css/codemirror.css: -------------------------------------------------------------------------------- 1 | /* BASICS */ 2 | 3 | .CodeMirror { 4 | /* Set height, width, borders, and global font properties here */ 5 | font-family: monospace; 6 | height: 100%; 7 | color: black; 8 | direction: ltr; 9 | } 10 | 11 | /* PADDING */ 12 | 13 | .CodeMirror-lines { 14 | padding: 4px 0; /* Vertical padding around content */ 15 | } 16 | .CodeMirror pre.CodeMirror-line, 17 | .CodeMirror pre.CodeMirror-line-like { 18 | padding: 0 4px; /* Horizontal padding of content */ 19 | } 20 | 21 | .CodeMirror-scrollbar-filler, .CodeMirror-gutter-filler { 22 | background-color: white; /* The little square between H and V scrollbars */ 23 | } 24 | 25 | /* GUTTER */ 26 | 27 | .CodeMirror-gutters { 28 | border-right: 1px solid #ddd; 29 | background-color: #f7f7f7; 30 | white-space: nowrap; 31 | } 32 | .CodeMirror-linenumbers {} 33 | .CodeMirror-linenumber { 34 | padding: 0 3px 0 5px; 35 | min-width: 20px; 36 | text-align: right; 37 | color: #999; 38 | white-space: nowrap; 39 | } 40 | 41 | .CodeMirror-guttermarker { color: black; } 42 | .CodeMirror-guttermarker-subtle { color: #999; } 43 | 44 | /* CURSOR */ 45 | 46 | .CodeMirror-cursor { 47 | border-left: 1px solid black; 48 | border-right: none; 49 | width: 0; 50 | } 51 | /* Shown when moving in bi-directional text */ 52 | .CodeMirror div.CodeMirror-secondarycursor { 53 | border-left: 1px solid silver; 54 | } 55 | .cm-fat-cursor .CodeMirror-cursor { 56 | width: auto; 57 | border: 0 !important; 58 | background: #7e7; 59 | } 60 | .cm-fat-cursor div.CodeMirror-cursors { 61 | z-index: 1; 62 | } 63 | .cm-fat-cursor-mark { 64 | background-color: rgba(20, 255, 20, 0.5); 65 | -webkit-animation: blink 1.06s steps(1) infinite; 66 | -moz-animation: blink 1.06s steps(1) infinite; 67 | animation: blink 1.06s steps(1) infinite; 68 | } 69 | .cm-animate-fat-cursor { 70 | width: auto; 71 | border: 0; 72 | -webkit-animation: blink 1.06s steps(1) infinite; 73 | -moz-animation: blink 1.06s steps(1) infinite; 74 | animation: blink 1.06s steps(1) infinite; 75 | background-color: #7e7; 76 | } 77 | @-moz-keyframes blink { 78 | 0% {} 79 | 50% { background-color: transparent; } 80 | 100% {} 81 | } 82 | @-webkit-keyframes blink { 83 | 0% {} 84 | 50% { background-color: transparent; } 85 | 100% {} 86 | } 87 | @keyframes blink { 88 | 0% {} 89 | 50% { background-color: transparent; } 90 | 100% {} 91 | } 92 | 93 | /* Can style cursor different in overwrite (non-insert) mode */ 94 | .CodeMirror-overwrite .CodeMirror-cursor {} 95 | 96 | .cm-tab { display: inline-block; text-decoration: inherit; } 97 | 98 | .CodeMirror-rulers { 99 | position: absolute; 100 | left: 0; right: 0; top: -50px; bottom: 0; 101 | overflow: hidden; 102 | } 103 | .CodeMirror-ruler { 104 | border-left: 1px solid #ccc; 105 | top: 0; bottom: 0; 106 | position: absolute; 107 | } 108 | 109 | /* DEFAULT THEME */ 110 | 111 | .cm-s-default .cm-header {color: blue;} 112 | .cm-s-default .cm-quote {color: #090;} 113 | .cm-negative {color: #d44;} 114 | .cm-positive {color: #292;} 115 | .cm-header, .cm-strong {font-weight: bold;} 116 | .cm-em {font-style: italic;} 117 | .cm-link {text-decoration: underline;} 118 | .cm-strikethrough {text-decoration: line-through;} 119 | 120 | .cm-s-default .cm-keyword {color: #708;} 121 | .cm-s-default .cm-atom {color: #219;} 122 | .cm-s-default .cm-number {color: #164;} 123 | .cm-s-default .cm-def {color: #00f;} 124 | .cm-s-default .cm-variable, 125 | .cm-s-default .cm-punctuation, 126 | .cm-s-default .cm-property, 127 | .cm-s-default .cm-operator {} 128 | .cm-s-default .cm-variable-2 {color: #05a;} 129 | .cm-s-default .cm-variable-3, .cm-s-default .cm-type {color: #085;} 130 | .cm-s-default .cm-comment {color: #a50;} 131 | .cm-s-default .cm-string {color: #a11;} 132 | .cm-s-default .cm-string-2 {color: #f50;} 133 | .cm-s-default .cm-meta {color: #555;} 134 | .cm-s-default .cm-qualifier {color: #555;} 135 | .cm-s-default .cm-builtin {color: #30a;} 136 | .cm-s-default .cm-bracket {color: #997;} 137 | .cm-s-default .cm-tag {color: #170;} 138 | .cm-s-default .cm-attribute {color: #00c;} 139 | .cm-s-default .cm-hr {color: #999;} 140 | .cm-s-default .cm-link {color: #00c;} 141 | 142 | .cm-s-default .cm-error {color: #f00;} 143 | .cm-invalidchar {color: #f00;} 144 | 145 | .CodeMirror-composing { border-bottom: 2px solid; } 146 | 147 | /* Default styles for common addons */ 148 | 149 | div.CodeMirror span.CodeMirror-matchingbracket {color: #0b0;} 150 | div.CodeMirror span.CodeMirror-nonmatchingbracket {color: #a22;} 151 | .CodeMirror-matchingtag { background: rgba(255, 150, 0, .3); } 152 | .CodeMirror-activeline-background {background: #e8f2ff;} 153 | 154 | /* STOP */ 155 | 156 | /* The rest of this file contains styles related to the mechanics of 157 | the editor. You probably shouldn't touch them. */ 158 | 159 | .CodeMirror { 160 | position: relative; 161 | overflow: hidden; 162 | background: white; 163 | } 164 | 165 | .CodeMirror-scroll { 166 | overflow: scroll !important; /* Things will break if this is overridden */ 167 | /* 30px is the magic margin used to hide the element's real scrollbars */ 168 | /* See overflow: hidden in .CodeMirror */ 169 | margin-bottom: -30px; margin-right: -30px; 170 | padding-bottom: 30px; 171 | height: 100%; 172 | outline: none; /* Prevent dragging from highlighting the element */ 173 | position: relative; 174 | } 175 | .CodeMirror-sizer { 176 | position: relative; 177 | border-right: 30px solid transparent; 178 | } 179 | 180 | /* The fake, visible scrollbars. Used to force redraw during scrolling 181 | before actual scrolling happens, thus preventing shaking and 182 | flickering artifacts. */ 183 | .CodeMirror-vscrollbar, .CodeMirror-hscrollbar, .CodeMirror-scrollbar-filler, .CodeMirror-gutter-filler { 184 | position: absolute; 185 | z-index: 6; 186 | display: none; 187 | } 188 | .CodeMirror-vscrollbar { 189 | right: 0; top: 0; 190 | overflow-x: hidden; 191 | overflow-y: scroll; 192 | } 193 | .CodeMirror-hscrollbar { 194 | bottom: 0; left: 0; 195 | overflow-y: hidden; 196 | overflow-x: scroll; 197 | } 198 | .CodeMirror-scrollbar-filler { 199 | right: 0; bottom: 0; 200 | } 201 | .CodeMirror-gutter-filler { 202 | left: 0; bottom: 0; 203 | } 204 | 205 | .CodeMirror-gutters { 206 | position: absolute; left: 0; top: 0; 207 | min-height: 100%; 208 | z-index: 3; 209 | } 210 | .CodeMirror-gutter { 211 | white-space: normal; 212 | height: 100%; 213 | display: inline-block; 214 | vertical-align: top; 215 | margin-bottom: -30px; 216 | } 217 | .CodeMirror-gutter-wrapper { 218 | position: absolute; 219 | z-index: 4; 220 | background: none !important; 221 | border: none !important; 222 | } 223 | .CodeMirror-gutter-background { 224 | position: absolute; 225 | top: 0; bottom: 0; 226 | z-index: 4; 227 | } 228 | .CodeMirror-gutter-elt { 229 | position: absolute; 230 | cursor: default; 231 | z-index: 4; 232 | } 233 | .CodeMirror-gutter-wrapper ::selection { background-color: transparent } 234 | .CodeMirror-gutter-wrapper ::-moz-selection { background-color: transparent } 235 | 236 | .CodeMirror-lines { 237 | cursor: text; 238 | min-height: 1px; /* prevents collapsing before first draw */ 239 | } 240 | .CodeMirror pre.CodeMirror-line, 241 | .CodeMirror pre.CodeMirror-line-like { 242 | /* Reset some styles that the rest of the page might have set */ 243 | -moz-border-radius: 0; -webkit-border-radius: 0; border-radius: 0; 244 | border-width: 0; 245 | background: transparent; 246 | font-family: inherit; 247 | font-size: inherit; 248 | margin: 0; 249 | white-space: pre; 250 | word-wrap: normal; 251 | line-height: inherit; 252 | color: inherit; 253 | z-index: 2; 254 | position: relative; 255 | overflow: visible; 256 | -webkit-tap-highlight-color: transparent; 257 | -webkit-font-variant-ligatures: contextual; 258 | font-variant-ligatures: contextual; 259 | } 260 | .CodeMirror-wrap pre.CodeMirror-line, 261 | .CodeMirror-wrap pre.CodeMirror-line-like { 262 | word-wrap: break-word; 263 | white-space: pre-wrap; 264 | word-break: normal; 265 | } 266 | 267 | .CodeMirror-linebackground { 268 | position: absolute; 269 | left: 0; right: 0; top: 0; bottom: 0; 270 | z-index: 0; 271 | } 272 | 273 | .CodeMirror-linewidget { 274 | position: relative; 275 | z-index: 2; 276 | padding: 0.1px; /* Force widget margins to stay inside of the container */ 277 | } 278 | 279 | .CodeMirror-widget {} 280 | 281 | .CodeMirror-rtl pre { direction: rtl; } 282 | 283 | .CodeMirror-code { 284 | outline: none; 285 | } 286 | 287 | /* Force content-box sizing for the elements where we expect it */ 288 | .CodeMirror-scroll, 289 | .CodeMirror-sizer, 290 | .CodeMirror-gutter, 291 | .CodeMirror-gutters, 292 | .CodeMirror-linenumber { 293 | -moz-box-sizing: content-box; 294 | box-sizing: content-box; 295 | } 296 | 297 | .CodeMirror-measure { 298 | position: absolute; 299 | width: 100%; 300 | height: 0; 301 | overflow: hidden; 302 | visibility: hidden; 303 | } 304 | 305 | .CodeMirror-cursor { 306 | position: absolute; 307 | pointer-events: none; 308 | } 309 | .CodeMirror-measure pre { position: static; } 310 | 311 | div.CodeMirror-cursors { 312 | visibility: hidden; 313 | position: relative; 314 | z-index: 3; 315 | } 316 | div.CodeMirror-dragcursors { 317 | visibility: visible; 318 | } 319 | 320 | .CodeMirror-focused div.CodeMirror-cursors { 321 | visibility: visible; 322 | } 323 | 324 | .CodeMirror-selected { background: #d9d9d9; } 325 | .CodeMirror-focused .CodeMirror-selected { background: #d7d4f0; } 326 | .CodeMirror-crosshair { cursor: crosshair; } 327 | .CodeMirror-line::selection, .CodeMirror-line > span::selection, .CodeMirror-line > span > span::selection { background: #d7d4f0; } 328 | .CodeMirror-line::-moz-selection, .CodeMirror-line > span::-moz-selection, .CodeMirror-line > span > span::-moz-selection { background: #d7d4f0; } 329 | 330 | .cm-searching { 331 | background-color: #ffa; 332 | background-color: rgba(255, 255, 0, .4); 333 | } 334 | 335 | /* Used to force a border model for a node */ 336 | .cm-force-border { padding-right: .1px; } 337 | 338 | @media print { 339 | /* Hide the cursor when printing */ 340 | .CodeMirror div.CodeMirror-cursors { 341 | visibility: hidden; 342 | } 343 | } 344 | 345 | /* See issue #2901 */ 346 | .cm-tab-wrap-hack:after { content: ''; } 347 | 348 | /* Help users use markselection to safely style text background */ 349 | span.CodeMirror-selectedtext { background: none; } 350 | -------------------------------------------------------------------------------- /src/main/resources/static/css/style.css: -------------------------------------------------------------------------------- 1 | .div-shadow { 2 | margin-top: 30px !important; 3 | width: 800px; 4 | height: 500px; 5 | padding: 10px; 6 | } 7 | 8 | #code-editor { 9 | width: 100% !important; 10 | height: 100% !important; 11 | background-color: white; 12 | } 13 | 14 | .alert-span { 15 | padding: 3px !important; 16 | margin-bottom: 0rem !important; 17 | } -------------------------------------------------------------------------------- /src/main/resources/static/model/clike.js: -------------------------------------------------------------------------------- 1 | // CodeMirror, copyright (c) by Marijn Haverbeke and others 2 | // Distributed under an MIT license: https://codemirror.net/LICENSE 3 | 4 | (function(mod) { 5 | if (typeof exports == "object" && typeof module == "object") // CommonJS 6 | mod(require("../../lib/codemirror")); 7 | else if (typeof define == "function" && define.amd) // AMD 8 | define(["../../lib/codemirror"], mod); 9 | else // Plain browser env 10 | mod(CodeMirror); 11 | })(function(CodeMirror) { 12 | "use strict"; 13 | 14 | function Context(indented, column, type, info, align, prev) { 15 | this.indented = indented; 16 | this.column = column; 17 | this.type = type; 18 | this.info = info; 19 | this.align = align; 20 | this.prev = prev; 21 | } 22 | function pushContext(state, col, type, info) { 23 | var indent = state.indented; 24 | if (state.context && state.context.type == "statement" && type != "statement") 25 | indent = state.context.indented; 26 | return state.context = new Context(indent, col, type, info, null, state.context); 27 | } 28 | function popContext(state) { 29 | var t = state.context.type; 30 | if (t == ")" || t == "]" || t == "}") 31 | state.indented = state.context.indented; 32 | return state.context = state.context.prev; 33 | } 34 | 35 | function typeBefore(stream, state, pos) { 36 | if (state.prevToken == "variable" || state.prevToken == "type") return true; 37 | if (/\S(?:[^- ]>|[*\]])\s*$|\*$/.test(stream.string.slice(0, pos))) return true; 38 | if (state.typeAtEndOfLine && stream.column() == stream.indentation()) return true; 39 | } 40 | 41 | function isTopScope(context) { 42 | for (;;) { 43 | if (!context || context.type == "top") return true; 44 | if (context.type == "}" && context.prev.info != "namespace") return false; 45 | context = context.prev; 46 | } 47 | } 48 | 49 | CodeMirror.defineMode("clike", function(config, parserConfig) { 50 | var indentUnit = config.indentUnit, 51 | statementIndentUnit = parserConfig.statementIndentUnit || indentUnit, 52 | dontAlignCalls = parserConfig.dontAlignCalls, 53 | keywords = parserConfig.keywords || {}, 54 | types = parserConfig.types || {}, 55 | builtin = parserConfig.builtin || {}, 56 | blockKeywords = parserConfig.blockKeywords || {}, 57 | defKeywords = parserConfig.defKeywords || {}, 58 | atoms = parserConfig.atoms || {}, 59 | hooks = parserConfig.hooks || {}, 60 | multiLineStrings = parserConfig.multiLineStrings, 61 | indentStatements = parserConfig.indentStatements !== false, 62 | indentSwitch = parserConfig.indentSwitch !== false, 63 | namespaceSeparator = parserConfig.namespaceSeparator, 64 | isPunctuationChar = parserConfig.isPunctuationChar || /[\[\]{}\(\),;\:\.]/, 65 | numberStart = parserConfig.numberStart || /[\d\.]/, 66 | number = parserConfig.number || /^(?:0x[a-f\d]+|0b[01]+|(?:\d+\.?\d*|\.\d+)(?:e[-+]?\d+)?)(u|ll?|l|f)?/i, 67 | isOperatorChar = parserConfig.isOperatorChar || /[+\-*&%=<>!?|\/]/, 68 | isIdentifierChar = parserConfig.isIdentifierChar || /[\w\$_\xa1-\uffff]/, 69 | // An optional function that takes a {string} token and returns true if it 70 | // should be treated as a builtin. 71 | isReservedIdentifier = parserConfig.isReservedIdentifier || false; 72 | 73 | var curPunc, isDefKeyword; 74 | 75 | function tokenBase(stream, state) { 76 | var ch = stream.next(); 77 | if (hooks[ch]) { 78 | var result = hooks[ch](stream, state); 79 | if (result !== false) return result; 80 | } 81 | if (ch == '"' || ch == "'") { 82 | state.tokenize = tokenString(ch); 83 | return state.tokenize(stream, state); 84 | } 85 | if (isPunctuationChar.test(ch)) { 86 | curPunc = ch; 87 | return null; 88 | } 89 | if (numberStart.test(ch)) { 90 | stream.backUp(1) 91 | if (stream.match(number)) return "number" 92 | stream.next() 93 | } 94 | if (ch == "/") { 95 | if (stream.eat("*")) { 96 | state.tokenize = tokenComment; 97 | return tokenComment(stream, state); 98 | } 99 | if (stream.eat("/")) { 100 | stream.skipToEnd(); 101 | return "comment"; 102 | } 103 | } 104 | if (isOperatorChar.test(ch)) { 105 | while (!stream.match(/^\/[\/*]/, false) && stream.eat(isOperatorChar)) {} 106 | return "operator"; 107 | } 108 | stream.eatWhile(isIdentifierChar); 109 | if (namespaceSeparator) while (stream.match(namespaceSeparator)) 110 | stream.eatWhile(isIdentifierChar); 111 | 112 | var cur = stream.current(); 113 | if (contains(keywords, cur)) { 114 | if (contains(blockKeywords, cur)) curPunc = "newstatement"; 115 | if (contains(defKeywords, cur)) isDefKeyword = true; 116 | return "keyword"; 117 | } 118 | if (contains(types, cur)) return "type"; 119 | if (contains(builtin, cur) 120 | || (isReservedIdentifier && isReservedIdentifier(cur))) { 121 | if (contains(blockKeywords, cur)) curPunc = "newstatement"; 122 | return "builtin"; 123 | } 124 | if (contains(atoms, cur)) return "atom"; 125 | return "variable"; 126 | } 127 | 128 | function tokenString(quote) { 129 | return function(stream, state) { 130 | var escaped = false, next, end = false; 131 | while ((next = stream.next()) != null) { 132 | if (next == quote && !escaped) {end = true; break;} 133 | escaped = !escaped && next == "\\"; 134 | } 135 | if (end || !(escaped || multiLineStrings)) 136 | state.tokenize = null; 137 | return "string"; 138 | }; 139 | } 140 | 141 | function tokenComment(stream, state) { 142 | var maybeEnd = false, ch; 143 | while (ch = stream.next()) { 144 | if (ch == "/" && maybeEnd) { 145 | state.tokenize = null; 146 | break; 147 | } 148 | maybeEnd = (ch == "*"); 149 | } 150 | return "comment"; 151 | } 152 | 153 | function maybeEOL(stream, state) { 154 | if (parserConfig.typeFirstDefinitions && stream.eol() && isTopScope(state.context)) 155 | state.typeAtEndOfLine = typeBefore(stream, state, stream.pos) 156 | } 157 | 158 | // Interface 159 | 160 | return { 161 | startState: function(basecolumn) { 162 | return { 163 | tokenize: null, 164 | context: new Context((basecolumn || 0) - indentUnit, 0, "top", null, false), 165 | indented: 0, 166 | startOfLine: true, 167 | prevToken: null 168 | }; 169 | }, 170 | 171 | token: function(stream, state) { 172 | var ctx = state.context; 173 | if (stream.sol()) { 174 | if (ctx.align == null) ctx.align = false; 175 | state.indented = stream.indentation(); 176 | state.startOfLine = true; 177 | } 178 | if (stream.eatSpace()) { maybeEOL(stream, state); return null; } 179 | curPunc = isDefKeyword = null; 180 | var style = (state.tokenize || tokenBase)(stream, state); 181 | if (style == "comment" || style == "meta") return style; 182 | if (ctx.align == null) ctx.align = true; 183 | 184 | if (curPunc == ";" || curPunc == ":" || (curPunc == "," && stream.match(/^\s*(?:\/\/.*)?$/, false))) 185 | while (state.context.type == "statement") popContext(state); 186 | else if (curPunc == "{") pushContext(state, stream.column(), "}"); 187 | else if (curPunc == "[") pushContext(state, stream.column(), "]"); 188 | else if (curPunc == "(") pushContext(state, stream.column(), ")"); 189 | else if (curPunc == "}") { 190 | while (ctx.type == "statement") ctx = popContext(state); 191 | if (ctx.type == "}") ctx = popContext(state); 192 | while (ctx.type == "statement") ctx = popContext(state); 193 | } 194 | else if (curPunc == ctx.type) popContext(state); 195 | else if (indentStatements && 196 | (((ctx.type == "}" || ctx.type == "top") && curPunc != ";") || 197 | (ctx.type == "statement" && curPunc == "newstatement"))) { 198 | pushContext(state, stream.column(), "statement", stream.current()); 199 | } 200 | 201 | if (style == "variable" && 202 | ((state.prevToken == "def" || 203 | (parserConfig.typeFirstDefinitions && typeBefore(stream, state, stream.start) && 204 | isTopScope(state.context) && stream.match(/^\s*\(/, false))))) 205 | style = "def"; 206 | 207 | if (hooks.token) { 208 | var result = hooks.token(stream, state, style); 209 | if (result !== undefined) style = result; 210 | } 211 | 212 | if (style == "def" && parserConfig.styleDefs === false) style = "variable"; 213 | 214 | state.startOfLine = false; 215 | state.prevToken = isDefKeyword ? "def" : style || curPunc; 216 | maybeEOL(stream, state); 217 | return style; 218 | }, 219 | 220 | indent: function(state, textAfter) { 221 | if (state.tokenize != tokenBase && state.tokenize != null || state.typeAtEndOfLine) return CodeMirror.Pass; 222 | var ctx = state.context, firstChar = textAfter && textAfter.charAt(0); 223 | var closing = firstChar == ctx.type; 224 | if (ctx.type == "statement" && firstChar == "}") ctx = ctx.prev; 225 | if (parserConfig.dontIndentStatements) 226 | while (ctx.type == "statement" && parserConfig.dontIndentStatements.test(ctx.info)) 227 | ctx = ctx.prev 228 | if (hooks.indent) { 229 | var hook = hooks.indent(state, ctx, textAfter, indentUnit); 230 | if (typeof hook == "number") return hook 231 | } 232 | var switchBlock = ctx.prev && ctx.prev.info == "switch"; 233 | if (parserConfig.allmanIndentation && /[{(]/.test(firstChar)) { 234 | while (ctx.type != "top" && ctx.type != "}") ctx = ctx.prev 235 | return ctx.indented 236 | } 237 | if (ctx.type == "statement") 238 | return ctx.indented + (firstChar == "{" ? 0 : statementIndentUnit); 239 | if (ctx.align && (!dontAlignCalls || ctx.type != ")")) 240 | return ctx.column + (closing ? 0 : 1); 241 | if (ctx.type == ")" && !closing) 242 | return ctx.indented + statementIndentUnit; 243 | 244 | return ctx.indented + (closing ? 0 : indentUnit) + 245 | (!closing && switchBlock && !/^(?:case|default)\b/.test(textAfter) ? indentUnit : 0); 246 | }, 247 | 248 | electricInput: indentSwitch ? /^\s*(?:case .*?:|default:|\{\}?|\})$/ : /^\s*[{}]$/, 249 | blockCommentStart: "/*", 250 | blockCommentEnd: "*/", 251 | blockCommentContinue: " * ", 252 | lineComment: "//", 253 | fold: "brace" 254 | }; 255 | }); 256 | 257 | function words(str) { 258 | var obj = {}, words = str.split(" "); 259 | for (var i = 0; i < words.length; ++i) obj[words[i]] = true; 260 | return obj; 261 | } 262 | function contains(words, word) { 263 | if (typeof words === "function") { 264 | return words(word); 265 | } else { 266 | return words.propertyIsEnumerable(word); 267 | } 268 | } 269 | var cKeywords = "auto if break case register continue return default do sizeof " + 270 | "static else struct switch extern typedef union for goto while enum const " + 271 | "volatile inline restrict asm fortran"; 272 | 273 | // Keywords from https://en.cppreference.com/w/cpp/keyword includes C++20. 274 | var cppKeywords = "alignas alignof and and_eq audit axiom bitand bitor catch " + 275 | "class compl concept constexpr const_cast decltype delete dynamic_cast " + 276 | "explicit export final friend import module mutable namespace new noexcept " + 277 | "not not_eq operator or or_eq override private protected public " + 278 | "reinterpret_cast requires static_assert static_cast template this " + 279 | "thread_local throw try typeid typename using virtual xor xor_eq"; 280 | 281 | var objCKeywords = "bycopy byref in inout oneway out self super atomic nonatomic retain copy " + 282 | "readwrite readonly strong weak assign typeof nullable nonnull null_resettable _cmd " + 283 | "@interface @implementation @end @protocol @encode @property @synthesize @dynamic @class " + 284 | "@public @package @private @protected @required @optional @try @catch @finally @import " + 285 | "@selector @encode @defs @synchronized @autoreleasepool @compatibility_alias @available"; 286 | 287 | var objCBuiltins = "FOUNDATION_EXPORT FOUNDATION_EXTERN NS_INLINE NS_FORMAT_FUNCTION " + 288 | " NS_RETURNS_RETAINEDNS_ERROR_ENUM NS_RETURNS_NOT_RETAINED NS_RETURNS_INNER_POINTER " + 289 | "NS_DESIGNATED_INITIALIZER NS_ENUM NS_OPTIONS NS_REQUIRES_NIL_TERMINATION " + 290 | "NS_ASSUME_NONNULL_BEGIN NS_ASSUME_NONNULL_END NS_SWIFT_NAME NS_REFINED_FOR_SWIFT" 291 | 292 | // Do not use this. Use the cTypes function below. This is global just to avoid 293 | // excessive calls when cTypes is being called multiple times during a parse. 294 | var basicCTypes = words("int long char short double float unsigned signed " + 295 | "void bool"); 296 | 297 | // Do not use this. Use the objCTypes function below. This is global just to avoid 298 | // excessive calls when objCTypes is being called multiple times during a parse. 299 | var basicObjCTypes = words("SEL instancetype id Class Protocol BOOL"); 300 | 301 | // Returns true if identifier is a "C" type. 302 | // C type is defined as those that are reserved by the compiler (basicTypes), 303 | // and those that end in _t (Reserved by POSIX for types) 304 | // http://www.gnu.org/software/libc/manual/html_node/Reserved-Names.html 305 | function cTypes(identifier) { 306 | return contains(basicCTypes, identifier) || /.+_t$/.test(identifier); 307 | } 308 | 309 | // Returns true if identifier is a "Objective C" type. 310 | function objCTypes(identifier) { 311 | return cTypes(identifier) || contains(basicObjCTypes, identifier); 312 | } 313 | 314 | var cBlockKeywords = "case do else for if switch while struct enum union"; 315 | var cDefKeywords = "struct enum union"; 316 | 317 | function cppHook(stream, state) { 318 | if (!state.startOfLine) return false 319 | for (var ch, next = null; ch = stream.peek();) { 320 | if (ch == "\\" && stream.match(/^.$/)) { 321 | next = cppHook 322 | break 323 | } else if (ch == "/" && stream.match(/^\/[\/\*]/, false)) { 324 | break 325 | } 326 | stream.next() 327 | } 328 | state.tokenize = next 329 | return "meta" 330 | } 331 | 332 | function pointerHook(_stream, state) { 333 | if (state.prevToken == "type") return "type"; 334 | return false; 335 | } 336 | 337 | // For C and C++ (and ObjC): identifiers starting with __ 338 | // or _ followed by a capital letter are reserved for the compiler. 339 | function cIsReservedIdentifier(token) { 340 | if (!token || token.length < 2) return false; 341 | if (token[0] != '_') return false; 342 | return (token[1] == '_') || (token[1] !== token[1].toLowerCase()); 343 | } 344 | 345 | function cpp14Literal(stream) { 346 | stream.eatWhile(/[\w\.']/); 347 | return "number"; 348 | } 349 | 350 | function cpp11StringHook(stream, state) { 351 | stream.backUp(1); 352 | // Raw strings. 353 | if (stream.match(/(R|u8R|uR|UR|LR)/)) { 354 | var match = stream.match(/"([^\s\\()]{0,16})\(/); 355 | if (!match) { 356 | return false; 357 | } 358 | state.cpp11RawStringDelim = match[1]; 359 | state.tokenize = tokenRawString; 360 | return tokenRawString(stream, state); 361 | } 362 | // Unicode strings/chars. 363 | if (stream.match(/(u8|u|U|L)/)) { 364 | if (stream.match(/["']/, /* eat */ false)) { 365 | return "string"; 366 | } 367 | return false; 368 | } 369 | // Ignore this hook. 370 | stream.next(); 371 | return false; 372 | } 373 | 374 | function cppLooksLikeConstructor(word) { 375 | var lastTwo = /(\w+)::~?(\w+)$/.exec(word); 376 | return lastTwo && lastTwo[1] == lastTwo[2]; 377 | } 378 | 379 | // C#-style strings where "" escapes a quote. 380 | function tokenAtString(stream, state) { 381 | var next; 382 | while ((next = stream.next()) != null) { 383 | if (next == '"' && !stream.eat('"')) { 384 | state.tokenize = null; 385 | break; 386 | } 387 | } 388 | return "string"; 389 | } 390 | 391 | // C++11 raw string literal is "( anything )", where 392 | // can be a string up to 16 characters long. 393 | function tokenRawString(stream, state) { 394 | // Escape characters that have special regex meanings. 395 | var delim = state.cpp11RawStringDelim.replace(/[^\w\s]/g, '\\$&'); 396 | var match = stream.match(new RegExp(".*?\\)" + delim + '"')); 397 | if (match) 398 | state.tokenize = null; 399 | else 400 | stream.skipToEnd(); 401 | return "string"; 402 | } 403 | 404 | function def(mimes, mode) { 405 | if (typeof mimes == "string") mimes = [mimes]; 406 | var words = []; 407 | function add(obj) { 408 | if (obj) for (var prop in obj) if (obj.hasOwnProperty(prop)) 409 | words.push(prop); 410 | } 411 | add(mode.keywords); 412 | add(mode.types); 413 | add(mode.builtin); 414 | add(mode.atoms); 415 | if (words.length) { 416 | mode.helperType = mimes[0]; 417 | CodeMirror.registerHelper("hintWords", mimes[0], words); 418 | } 419 | 420 | for (var i = 0; i < mimes.length; ++i) 421 | CodeMirror.defineMIME(mimes[i], mode); 422 | } 423 | 424 | def(["text/x-csrc", "text/x-c", "text/x-chdr"], { 425 | name: "clike", 426 | keywords: words(cKeywords), 427 | types: cTypes, 428 | blockKeywords: words(cBlockKeywords), 429 | defKeywords: words(cDefKeywords), 430 | typeFirstDefinitions: true, 431 | atoms: words("NULL true false"), 432 | isReservedIdentifier: cIsReservedIdentifier, 433 | hooks: { 434 | "#": cppHook, 435 | "*": pointerHook, 436 | }, 437 | modeProps: {fold: ["brace", "include"]} 438 | }); 439 | 440 | def(["text/x-c++src", "text/x-c++hdr"], { 441 | name: "clike", 442 | keywords: words(cKeywords + " " + cppKeywords), 443 | types: cTypes, 444 | blockKeywords: words(cBlockKeywords + " class try catch"), 445 | defKeywords: words(cDefKeywords + " class namespace"), 446 | typeFirstDefinitions: true, 447 | atoms: words("true false NULL nullptr"), 448 | dontIndentStatements: /^template$/, 449 | isIdentifierChar: /[\w\$_~\xa1-\uffff]/, 450 | isReservedIdentifier: cIsReservedIdentifier, 451 | hooks: { 452 | "#": cppHook, 453 | "*": pointerHook, 454 | "u": cpp11StringHook, 455 | "U": cpp11StringHook, 456 | "L": cpp11StringHook, 457 | "R": cpp11StringHook, 458 | "0": cpp14Literal, 459 | "1": cpp14Literal, 460 | "2": cpp14Literal, 461 | "3": cpp14Literal, 462 | "4": cpp14Literal, 463 | "5": cpp14Literal, 464 | "6": cpp14Literal, 465 | "7": cpp14Literal, 466 | "8": cpp14Literal, 467 | "9": cpp14Literal, 468 | token: function(stream, state, style) { 469 | if (style == "variable" && stream.peek() == "(" && 470 | (state.prevToken == ";" || state.prevToken == null || 471 | state.prevToken == "}") && 472 | cppLooksLikeConstructor(stream.current())) 473 | return "def"; 474 | } 475 | }, 476 | namespaceSeparator: "::", 477 | modeProps: {fold: ["brace", "include"]} 478 | }); 479 | 480 | def("text/x-java", { 481 | name: "clike", 482 | keywords: words("abstract assert break case catch class const continue default " + 483 | "do else enum extends final finally for goto if implements import " + 484 | "instanceof interface native new package private protected public " + 485 | "return static strictfp super switch synchronized this throw throws transient " + 486 | "try volatile while @interface"), 487 | types: words("byte short int long float double boolean char void Boolean Byte Character Double Float " + 488 | "Integer Long Number Object Short String StringBuffer StringBuilder Void"), 489 | blockKeywords: words("catch class do else finally for if switch try while"), 490 | defKeywords: words("class interface enum @interface"), 491 | typeFirstDefinitions: true, 492 | atoms: words("true false null"), 493 | number: /^(?:0x[a-f\d_]+|0b[01_]+|(?:[\d_]+\.?\d*|\.\d+)(?:e[-+]?[\d_]+)?)(u|ll?|l|f)?/i, 494 | hooks: { 495 | "@": function(stream) { 496 | // Don't match the @interface keyword. 497 | if (stream.match('interface', false)) return false; 498 | 499 | stream.eatWhile(/[\w\$_]/); 500 | return "meta"; 501 | } 502 | }, 503 | modeProps: {fold: ["brace", "import"]} 504 | }); 505 | 506 | def("text/x-csharp", { 507 | name: "clike", 508 | keywords: words("abstract as async await base break case catch checked class const continue" + 509 | " default delegate do else enum event explicit extern finally fixed for" + 510 | " foreach goto if implicit in interface internal is lock namespace new" + 511 | " operator out override params private protected public readonly ref return sealed" + 512 | " sizeof stackalloc static struct switch this throw try typeof unchecked" + 513 | " unsafe using virtual void volatile while add alias ascending descending dynamic from get" + 514 | " global group into join let orderby partial remove select set value var yield"), 515 | types: words("Action Boolean Byte Char DateTime DateTimeOffset Decimal Double Func" + 516 | " Guid Int16 Int32 Int64 Object SByte Single String Task TimeSpan UInt16 UInt32" + 517 | " UInt64 bool byte char decimal double short int long object" + 518 | " sbyte float string ushort uint ulong"), 519 | blockKeywords: words("catch class do else finally for foreach if struct switch try while"), 520 | defKeywords: words("class interface namespace struct var"), 521 | typeFirstDefinitions: true, 522 | atoms: words("true false null"), 523 | hooks: { 524 | "@": function(stream, state) { 525 | if (stream.eat('"')) { 526 | state.tokenize = tokenAtString; 527 | return tokenAtString(stream, state); 528 | } 529 | stream.eatWhile(/[\w\$_]/); 530 | return "meta"; 531 | } 532 | } 533 | }); 534 | 535 | function tokenTripleString(stream, state) { 536 | var escaped = false; 537 | while (!stream.eol()) { 538 | if (!escaped && stream.match('"""')) { 539 | state.tokenize = null; 540 | break; 541 | } 542 | escaped = stream.next() == "\\" && !escaped; 543 | } 544 | return "string"; 545 | } 546 | 547 | function tokenNestedComment(depth) { 548 | return function (stream, state) { 549 | var ch 550 | while (ch = stream.next()) { 551 | if (ch == "*" && stream.eat("/")) { 552 | if (depth == 1) { 553 | state.tokenize = null 554 | break 555 | } else { 556 | state.tokenize = tokenNestedComment(depth - 1) 557 | return state.tokenize(stream, state) 558 | } 559 | } else if (ch == "/" && stream.eat("*")) { 560 | state.tokenize = tokenNestedComment(depth + 1) 561 | return state.tokenize(stream, state) 562 | } 563 | } 564 | return "comment" 565 | } 566 | } 567 | 568 | def("text/x-scala", { 569 | name: "clike", 570 | keywords: words( 571 | /* scala */ 572 | "abstract case catch class def do else extends final finally for forSome if " + 573 | "implicit import lazy match new null object override package private protected return " + 574 | "sealed super this throw trait try type val var while with yield _ " + 575 | 576 | /* package scala */ 577 | "assert assume require print println printf readLine readBoolean readByte readShort " + 578 | "readChar readInt readLong readFloat readDouble" 579 | ), 580 | types: words( 581 | "AnyVal App Application Array BufferedIterator BigDecimal BigInt Char Console Either " + 582 | "Enumeration Equiv Error Exception Fractional Function IndexedSeq Int Integral Iterable " + 583 | "Iterator List Map Numeric Nil NotNull Option Ordered Ordering PartialFunction PartialOrdering " + 584 | "Product Proxy Range Responder Seq Serializable Set Specializable Stream StringBuilder " + 585 | "StringContext Symbol Throwable Traversable TraversableOnce Tuple Unit Vector " + 586 | 587 | /* package java.lang */ 588 | "Boolean Byte Character CharSequence Class ClassLoader Cloneable Comparable " + 589 | "Compiler Double Exception Float Integer Long Math Number Object Package Pair Process " + 590 | "Runtime Runnable SecurityManager Short StackTraceElement StrictMath String " + 591 | "StringBuffer System Thread ThreadGroup ThreadLocal Throwable Triple Void" 592 | ), 593 | multiLineStrings: true, 594 | blockKeywords: words("catch class enum do else finally for forSome if match switch try while"), 595 | defKeywords: words("class enum def object package trait type val var"), 596 | atoms: words("true false null"), 597 | indentStatements: false, 598 | indentSwitch: false, 599 | isOperatorChar: /[+\-*&%=<>!?|\/#:@]/, 600 | hooks: { 601 | "@": function(stream) { 602 | stream.eatWhile(/[\w\$_]/); 603 | return "meta"; 604 | }, 605 | '"': function(stream, state) { 606 | if (!stream.match('""')) return false; 607 | state.tokenize = tokenTripleString; 608 | return state.tokenize(stream, state); 609 | }, 610 | "'": function(stream) { 611 | stream.eatWhile(/[\w\$_\xa1-\uffff]/); 612 | return "atom"; 613 | }, 614 | "=": function(stream, state) { 615 | var cx = state.context 616 | if (cx.type == "}" && cx.align && stream.eat(">")) { 617 | state.context = new Context(cx.indented, cx.column, cx.type, cx.info, null, cx.prev) 618 | return "operator" 619 | } else { 620 | return false 621 | } 622 | }, 623 | 624 | "/": function(stream, state) { 625 | if (!stream.eat("*")) return false 626 | state.tokenize = tokenNestedComment(1) 627 | return state.tokenize(stream, state) 628 | } 629 | }, 630 | modeProps: {closeBrackets: {pairs: '()[]{}""', triples: '"'}} 631 | }); 632 | 633 | function tokenKotlinString(tripleString){ 634 | return function (stream, state) { 635 | var escaped = false, next, end = false; 636 | while (!stream.eol()) { 637 | if (!tripleString && !escaped && stream.match('"') ) {end = true; break;} 638 | if (tripleString && stream.match('"""')) {end = true; break;} 639 | next = stream.next(); 640 | if(!escaped && next == "$" && stream.match('{')) 641 | stream.skipTo("}"); 642 | escaped = !escaped && next == "\\" && !tripleString; 643 | } 644 | if (end || !tripleString) 645 | state.tokenize = null; 646 | return "string"; 647 | } 648 | } 649 | 650 | def("text/x-kotlin", { 651 | name: "clike", 652 | keywords: words( 653 | /*keywords*/ 654 | "package as typealias class interface this super val operator " + 655 | "var fun for is in This throw return annotation " + 656 | "break continue object if else while do try when !in !is as? " + 657 | 658 | /*soft keywords*/ 659 | "file import where by get set abstract enum open inner override private public internal " + 660 | "protected catch finally out final vararg reified dynamic companion constructor init " + 661 | "sealed field property receiver param sparam lateinit data inline noinline tailrec " + 662 | "external annotation crossinline const operator infix suspend actual expect setparam" 663 | ), 664 | types: words( 665 | /* package java.lang */ 666 | "Boolean Byte Character CharSequence Class ClassLoader Cloneable Comparable " + 667 | "Compiler Double Exception Float Integer Long Math Number Object Package Pair Process " + 668 | "Runtime Runnable SecurityManager Short StackTraceElement StrictMath String " + 669 | "StringBuffer System Thread ThreadGroup ThreadLocal Throwable Triple Void Annotation Any BooleanArray " + 670 | "ByteArray Char CharArray DeprecationLevel DoubleArray Enum FloatArray Function Int IntArray Lazy " + 671 | "LazyThreadSafetyMode LongArray Nothing ShortArray Unit" 672 | ), 673 | intendSwitch: false, 674 | indentStatements: false, 675 | multiLineStrings: true, 676 | number: /^(?:0x[a-f\d_]+|0b[01_]+|(?:[\d_]+(\.\d+)?|\.\d+)(?:e[-+]?[\d_]+)?)(u|ll?|l|f)?/i, 677 | blockKeywords: words("catch class do else finally for if where try while enum"), 678 | defKeywords: words("class val var object interface fun"), 679 | atoms: words("true false null this"), 680 | hooks: { 681 | "@": function(stream) { 682 | stream.eatWhile(/[\w\$_]/); 683 | return "meta"; 684 | }, 685 | '*': function(_stream, state) { 686 | return state.prevToken == '.' ? 'variable' : 'operator'; 687 | }, 688 | '"': function(stream, state) { 689 | state.tokenize = tokenKotlinString(stream.match('""')); 690 | return state.tokenize(stream, state); 691 | }, 692 | "/": function(stream, state) { 693 | if (!stream.eat("*")) return false; 694 | state.tokenize = tokenNestedComment(1); 695 | return state.tokenize(stream, state) 696 | }, 697 | indent: function(state, ctx, textAfter, indentUnit) { 698 | var firstChar = textAfter && textAfter.charAt(0); 699 | if ((state.prevToken == "}" || state.prevToken == ")") && textAfter == "") 700 | return state.indented; 701 | if ((state.prevToken == "operator" && textAfter != "}" && state.context.type != "}") || 702 | state.prevToken == "variable" && firstChar == "." || 703 | (state.prevToken == "}" || state.prevToken == ")") && firstChar == ".") 704 | return indentUnit * 2 + ctx.indented; 705 | if (ctx.align && ctx.type == "}") 706 | return ctx.indented + (state.context.type == (textAfter || "").charAt(0) ? 0 : indentUnit); 707 | } 708 | }, 709 | modeProps: {closeBrackets: {triples: '"'}} 710 | }); 711 | 712 | def(["x-shader/x-vertex", "x-shader/x-fragment"], { 713 | name: "clike", 714 | keywords: words("sampler1D sampler2D sampler3D samplerCube " + 715 | "sampler1DShadow sampler2DShadow " + 716 | "const attribute uniform varying " + 717 | "break continue discard return " + 718 | "for while do if else struct " + 719 | "in out inout"), 720 | types: words("float int bool void " + 721 | "vec2 vec3 vec4 ivec2 ivec3 ivec4 bvec2 bvec3 bvec4 " + 722 | "mat2 mat3 mat4"), 723 | blockKeywords: words("for while do if else struct"), 724 | builtin: words("radians degrees sin cos tan asin acos atan " + 725 | "pow exp log exp2 sqrt inversesqrt " + 726 | "abs sign floor ceil fract mod min max clamp mix step smoothstep " + 727 | "length distance dot cross normalize ftransform faceforward " + 728 | "reflect refract matrixCompMult " + 729 | "lessThan lessThanEqual greaterThan greaterThanEqual " + 730 | "equal notEqual any all not " + 731 | "texture1D texture1DProj texture1DLod texture1DProjLod " + 732 | "texture2D texture2DProj texture2DLod texture2DProjLod " + 733 | "texture3D texture3DProj texture3DLod texture3DProjLod " + 734 | "textureCube textureCubeLod " + 735 | "shadow1D shadow2D shadow1DProj shadow2DProj " + 736 | "shadow1DLod shadow2DLod shadow1DProjLod shadow2DProjLod " + 737 | "dFdx dFdy fwidth " + 738 | "noise1 noise2 noise3 noise4"), 739 | atoms: words("true false " + 740 | "gl_FragColor gl_SecondaryColor gl_Normal gl_Vertex " + 741 | "gl_MultiTexCoord0 gl_MultiTexCoord1 gl_MultiTexCoord2 gl_MultiTexCoord3 " + 742 | "gl_MultiTexCoord4 gl_MultiTexCoord5 gl_MultiTexCoord6 gl_MultiTexCoord7 " + 743 | "gl_FogCoord gl_PointCoord " + 744 | "gl_Position gl_PointSize gl_ClipVertex " + 745 | "gl_FrontColor gl_BackColor gl_FrontSecondaryColor gl_BackSecondaryColor " + 746 | "gl_TexCoord gl_FogFragCoord " + 747 | "gl_FragCoord gl_FrontFacing " + 748 | "gl_FragData gl_FragDepth " + 749 | "gl_ModelViewMatrix gl_ProjectionMatrix gl_ModelViewProjectionMatrix " + 750 | "gl_TextureMatrix gl_NormalMatrix gl_ModelViewMatrixInverse " + 751 | "gl_ProjectionMatrixInverse gl_ModelViewProjectionMatrixInverse " + 752 | "gl_TexureMatrixTranspose gl_ModelViewMatrixInverseTranspose " + 753 | "gl_ProjectionMatrixInverseTranspose " + 754 | "gl_ModelViewProjectionMatrixInverseTranspose " + 755 | "gl_TextureMatrixInverseTranspose " + 756 | "gl_NormalScale gl_DepthRange gl_ClipPlane " + 757 | "gl_Point gl_FrontMaterial gl_BackMaterial gl_LightSource gl_LightModel " + 758 | "gl_FrontLightModelProduct gl_BackLightModelProduct " + 759 | "gl_TextureColor gl_EyePlaneS gl_EyePlaneT gl_EyePlaneR gl_EyePlaneQ " + 760 | "gl_FogParameters " + 761 | "gl_MaxLights gl_MaxClipPlanes gl_MaxTextureUnits gl_MaxTextureCoords " + 762 | "gl_MaxVertexAttribs gl_MaxVertexUniformComponents gl_MaxVaryingFloats " + 763 | "gl_MaxVertexTextureImageUnits gl_MaxTextureImageUnits " + 764 | "gl_MaxFragmentUniformComponents gl_MaxCombineTextureImageUnits " + 765 | "gl_MaxDrawBuffers"), 766 | indentSwitch: false, 767 | hooks: {"#": cppHook}, 768 | modeProps: {fold: ["brace", "include"]} 769 | }); 770 | 771 | def("text/x-nesc", { 772 | name: "clike", 773 | keywords: words(cKeywords + " as atomic async call command component components configuration event generic " + 774 | "implementation includes interface module new norace nx_struct nx_union post provides " + 775 | "signal task uses abstract extends"), 776 | types: cTypes, 777 | blockKeywords: words(cBlockKeywords), 778 | atoms: words("null true false"), 779 | hooks: {"#": cppHook}, 780 | modeProps: {fold: ["brace", "include"]} 781 | }); 782 | 783 | def("text/x-objectivec", { 784 | name: "clike", 785 | keywords: words(cKeywords + " " + objCKeywords), 786 | types: objCTypes, 787 | builtin: words(objCBuiltins), 788 | blockKeywords: words(cBlockKeywords + " @synthesize @try @catch @finally @autoreleasepool @synchronized"), 789 | defKeywords: words(cDefKeywords + " @interface @implementation @protocol @class"), 790 | dontIndentStatements: /^@.*$/, 791 | typeFirstDefinitions: true, 792 | atoms: words("YES NO NULL Nil nil true false nullptr"), 793 | isReservedIdentifier: cIsReservedIdentifier, 794 | hooks: { 795 | "#": cppHook, 796 | "*": pointerHook, 797 | }, 798 | modeProps: {fold: ["brace", "include"]} 799 | }); 800 | 801 | def("text/x-objectivec++", { 802 | name: "clike", 803 | keywords: words(cKeywords + " " + objCKeywords + " " + cppKeywords), 804 | types: objCTypes, 805 | builtin: words(objCBuiltins), 806 | blockKeywords: words(cBlockKeywords + " @synthesize @try @catch @finally @autoreleasepool @synchronized class try catch"), 807 | defKeywords: words(cDefKeywords + " @interface @implementation @protocol @class class namespace"), 808 | dontIndentStatements: /^@.*$|^template$/, 809 | typeFirstDefinitions: true, 810 | atoms: words("YES NO NULL Nil nil true false nullptr"), 811 | isReservedIdentifier: cIsReservedIdentifier, 812 | hooks: { 813 | "#": cppHook, 814 | "*": pointerHook, 815 | "u": cpp11StringHook, 816 | "U": cpp11StringHook, 817 | "L": cpp11StringHook, 818 | "R": cpp11StringHook, 819 | "0": cpp14Literal, 820 | "1": cpp14Literal, 821 | "2": cpp14Literal, 822 | "3": cpp14Literal, 823 | "4": cpp14Literal, 824 | "5": cpp14Literal, 825 | "6": cpp14Literal, 826 | "7": cpp14Literal, 827 | "8": cpp14Literal, 828 | "9": cpp14Literal, 829 | token: function(stream, state, style) { 830 | if (style == "variable" && stream.peek() == "(" && 831 | (state.prevToken == ";" || state.prevToken == null || 832 | state.prevToken == "}") && 833 | cppLooksLikeConstructor(stream.current())) 834 | return "def"; 835 | } 836 | }, 837 | namespaceSeparator: "::", 838 | modeProps: {fold: ["brace", "include"]} 839 | }); 840 | 841 | def("text/x-squirrel", { 842 | name: "clike", 843 | keywords: words("base break clone continue const default delete enum extends function in class" + 844 | " foreach local resume return this throw typeof yield constructor instanceof static"), 845 | types: cTypes, 846 | blockKeywords: words("case catch class else for foreach if switch try while"), 847 | defKeywords: words("function local class"), 848 | typeFirstDefinitions: true, 849 | atoms: words("true false null"), 850 | hooks: {"#": cppHook}, 851 | modeProps: {fold: ["brace", "include"]} 852 | }); 853 | 854 | // Ceylon Strings need to deal with interpolation 855 | var stringTokenizer = null; 856 | function tokenCeylonString(type) { 857 | return function(stream, state) { 858 | var escaped = false, next, end = false; 859 | while (!stream.eol()) { 860 | if (!escaped && stream.match('"') && 861 | (type == "single" || stream.match('""'))) { 862 | end = true; 863 | break; 864 | } 865 | if (!escaped && stream.match('``')) { 866 | stringTokenizer = tokenCeylonString(type); 867 | end = true; 868 | break; 869 | } 870 | next = stream.next(); 871 | escaped = type == "single" && !escaped && next == "\\"; 872 | } 873 | if (end) 874 | state.tokenize = null; 875 | return "string"; 876 | } 877 | } 878 | 879 | def("text/x-ceylon", { 880 | name: "clike", 881 | keywords: words("abstracts alias assembly assert assign break case catch class continue dynamic else" + 882 | " exists extends finally for function given if import in interface is let module new" + 883 | " nonempty object of out outer package return satisfies super switch then this throw" + 884 | " try value void while"), 885 | types: function(word) { 886 | // In Ceylon all identifiers that start with an uppercase are types 887 | var first = word.charAt(0); 888 | return (first === first.toUpperCase() && first !== first.toLowerCase()); 889 | }, 890 | blockKeywords: words("case catch class dynamic else finally for function if interface module new object switch try while"), 891 | defKeywords: words("class dynamic function interface module object package value"), 892 | builtin: words("abstract actual aliased annotation by default deprecated doc final formal late license" + 893 | " native optional sealed see serializable shared suppressWarnings tagged throws variable"), 894 | isPunctuationChar: /[\[\]{}\(\),;\:\.`]/, 895 | isOperatorChar: /[+\-*&%=<>!?|^~:\/]/, 896 | numberStart: /[\d#$]/, 897 | number: /^(?:#[\da-fA-F_]+|\$[01_]+|[\d_]+[kMGTPmunpf]?|[\d_]+\.[\d_]+(?:[eE][-+]?\d+|[kMGTPmunpf]|)|)/i, 898 | multiLineStrings: true, 899 | typeFirstDefinitions: true, 900 | atoms: words("true false null larger smaller equal empty finished"), 901 | indentSwitch: false, 902 | styleDefs: false, 903 | hooks: { 904 | "@": function(stream) { 905 | stream.eatWhile(/[\w\$_]/); 906 | return "meta"; 907 | }, 908 | '"': function(stream, state) { 909 | state.tokenize = tokenCeylonString(stream.match('""') ? "triple" : "single"); 910 | return state.tokenize(stream, state); 911 | }, 912 | '`': function(stream, state) { 913 | if (!stringTokenizer || !stream.match('`')) return false; 914 | state.tokenize = stringTokenizer; 915 | stringTokenizer = null; 916 | return state.tokenize(stream, state); 917 | }, 918 | "'": function(stream) { 919 | stream.eatWhile(/[\w\$_\xa1-\uffff]/); 920 | return "atom"; 921 | }, 922 | token: function(_stream, state, style) { 923 | if ((style == "variable" || style == "type") && 924 | state.prevToken == ".") { 925 | return "variable-2"; 926 | } 927 | } 928 | }, 929 | modeProps: { 930 | fold: ["brace", "import"], 931 | closeBrackets: {triples: '"'} 932 | } 933 | }); 934 | 935 | }); 936 | -------------------------------------------------------------------------------- /src/main/resources/templates/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Title 6 | 7 | 8 | 9 | 10 | 11 | 12 |

Online Java Editor

13 | 14 |
15 |
16 | 17 |
18 |
19 |
20 | 24 | 25 |
26 |
27 |
28 |

执行结果: 29 | 成功 30 | 编译错误 31 |

32 |

33 | 34 |

35 |
36 |
37 | 38 | 39 | 40 | 41 | 42 | 86 | 87 | -------------------------------------------------------------------------------- /src/test/java/com/leisurexi/codeeditor/CodeEditorApplicationTests.java: -------------------------------------------------------------------------------- 1 | package com.leisurexi.codeeditor; 2 | 3 | import org.junit.jupiter.api.Test; 4 | import org.springframework.boot.test.context.SpringBootTest; 5 | 6 | @SpringBootTest 7 | class CodeEditorApplicationTests { 8 | 9 | @Test 10 | void contextLoads() { 11 | } 12 | 13 | } 14 | --------------------------------------------------------------------------------