mirror of https://github.com/abpframework/abp.git
committed by
GitHub
1319 changed files with 262153 additions and 2066 deletions
@ -0,0 +1,240 @@ |
|||
## ABP OpenIddict Modules |
|||
|
|||
## How to Install |
|||
|
|||
TODO: |
|||
|
|||
## User Interface |
|||
|
|||
This module implements the domain logic and database integrations, but not provides any UI. Management UI is useful if you need to add applications and scopes on the fly. In this case, you may build the management UI yourself or consider to purchase the [ABP Commercial](https://commercial.abp.io/) which provides the management UI for this module. |
|||
|
|||
## Relations to Other Modules |
|||
|
|||
This module is based on the [Identity Module](Identity.md) and have an [integration package](https://www.nuget.org/packages/Volo.Abp.Account.Web.IdentityServer) with the [Account Module](Account.md). |
|||
|
|||
## The module |
|||
|
|||
### Demo projects |
|||
|
|||
In the module's `app` directory there are six projects(including `angular`) |
|||
|
|||
* `OpenIddict.Demo.Server`: An abp application with integrated modules (has two `clients` and a `scope`). |
|||
* `OpenIddict.Demo.API`: ASP NET Core API application using JwtBearer authentication |
|||
* `OpenIddict.Demo.Client.Mvc`: ASP NET Core MVC application using `OpenIdConnect` for authentication |
|||
* `OpenIddict.Demo.Client.Console`: Use `IdentityModel` to test OpenIddict's various endpoints, and call the api of `OpenIddict.Demo.API` |
|||
* `OpenIddict.Demo.Client.BlazorWASM:` ASP NET Core Blazor application using `OidcAuthentication` for authentication |
|||
* `angular`: An angular application that integrates the abp ng modules and uses oauth for authentication |
|||
|
|||
#### How to run? |
|||
|
|||
Confirm the connection string of `appsettings.json` in the `OpenIddict.Demo.Server` project. Running the project will automatically create the database and initialize the data. |
|||
After running the `OpenIddict.Demo.API` project, then you can run the rest of the projects to test. |
|||
|
|||
### Domain module |
|||
|
|||
There are four main entities included in this module. |
|||
|
|||
* OpenIddictApplication: **Represents applications(client)** |
|||
* OpenIddictScope: **Represents scopes** |
|||
* OpenIddictAuthorization: **Represents authorizations, Track of logical chains of tokens and user consent..** |
|||
* OpenIddictToken: **Represents various tokens.** |
|||
|
|||
Domain also implements four store interfaces in OpenIddict, OpenIddict uses store to manage entities, corresponding to the above four entities, Custom entity repository is used in the store. |
|||
|
|||
|
|||
```cs |
|||
//Manager |
|||
OpenIddictApplicationManager |
|||
OpenIddictScopeManager |
|||
OpenIddictAuthorizationManager |
|||
OpenIddictTokenManager |
|||
|
|||
//Store |
|||
IOpenIddictApplicationStore |
|||
IOpenIddictScopeStore |
|||
IOpenIddictAuthorizationStore |
|||
IOpenIddictTokenStore |
|||
|
|||
//Repository |
|||
IOpenIddictApplicationRepository |
|||
IOpenIddictScopeRepository |
|||
IOpenIddictAuthorizationRepository |
|||
IOpenIddictTokenRepository |
|||
``` |
|||
|
|||
We enabled most of OpenIddict's features in the `AddOpenIddict` method, You can change OpenIddict's related builder options via `PreConfigure`. |
|||
|
|||
```cs |
|||
PreConfigure<OpenIddictBuilder>(builder => |
|||
{ |
|||
//builder |
|||
}); |
|||
|
|||
PreConfigure<OpenIddictCoreBuilder>(builder => |
|||
{ |
|||
//builder |
|||
}); |
|||
|
|||
PreConfigure<OpenIddictServerBuilder>(builder => |
|||
{ |
|||
//builder |
|||
}); |
|||
``` |
|||
|
|||
#### AbpOpenIddictOptions |
|||
|
|||
`UpdateAbpClaimTypes(default: true)`: Updates AbpClaimTypes to be compatible with identity server claims. |
|||
`AddDevelopmentEncryptionAndSigningCertificate(default: true)`: Registers (and generates if necessary) a user-specific development encryption/development signing certificate. |
|||
|
|||
You can also change this options via `PreConfigure`. |
|||
|
|||
#### Automatically removing orphaned tokens/authorizations |
|||
|
|||
There is a background task in the `Domain` module (`enabled by default`) that automatically removes orphaned tokens/authorizations, you can configure `TokenCleanupOptions` to manage it. |
|||
|
|||
### ASP NET Core module |
|||
|
|||
This module integrates ASP NET Core, with built-in MVC controllers for four protocols. It uses OpenIddict's [Pass-through mode](https://documentation.openiddict.com/guides/index.html#pass-through-mode). |
|||
|
|||
```cs |
|||
AuthorizeController -> connect/authorize |
|||
TokenController -> connect/token |
|||
LogoutController -> connect/logout |
|||
UserInfoController -> connect/userinfo |
|||
``` |
|||
|
|||
> We will implement the related functions of **device flow** in the PRO module.. |
|||
|
|||
#### How to control claims in access_token and id_token |
|||
|
|||
You can use the [Claims Principal Factory](https://docs.abp.io/en/abp/latest/Authorization#claims-principal-factory) to add/remove claims to the `ClaimsPrincipal`. |
|||
|
|||
The `AbpDefaultOpenIddictClaimDestinationsProvider` service will add `Name`, `Email` and `Role` types of Claims to `access_token` and `id_token`, other claims are only added to `access_token` by default, and remove the `SecurityStampClaimType` secret claim of `Identity`. |
|||
|
|||
You can create a service that inherits from `IAbpOpenIddictClaimDestinationsProvider` and add it to DI to fully control the destinations of claims |
|||
|
|||
```cs |
|||
public class MyClaimDestinationsProvider : IAbpOpenIddictClaimDestinationsProvider, ITransientDependency |
|||
{ |
|||
public virtual Task SetDestinationsAsync(AbpOpenIddictClaimDestinationsProviderContext context) |
|||
{ |
|||
// ... |
|||
return Task.CompletedTask; |
|||
} |
|||
} |
|||
|
|||
Configure<AbpOpenIddictClaimDestinationsOptions>(options => |
|||
{ |
|||
options.ClaimDestinationsProvider.Add<MyClaimDestinationsProvider>(); |
|||
}); |
|||
``` |
|||
|
|||
For detailed information, please refer to: [OpenIddict claim destinations](https://documentation.openiddict.com/configuration/claim-destinations.html) |
|||
|
|||
#### About Validation |
|||
|
|||
The `OpenIddict.Validation.AspNetCore` and `OpenIddict.Validation` are not integrated in the module, we use the authentication component provided by Microsoft. If you are more familiar with it, you can use it in your project. |
|||
|
|||
|
|||
### EF Core module |
|||
|
|||
Implements the above four repository interfaces. |
|||
|
|||
### MongoDB module |
|||
|
|||
Implements the above four repository interfaces. |
|||
|
|||
|
|||
## OpenIddict |
|||
|
|||
### Documentation |
|||
|
|||
For more details about OpenIddict, please refer to its official documentation and Github. |
|||
|
|||
https://documentation.openiddict.com |
|||
|
|||
https://github.com/openiddict/openiddict-core#resources |
|||
|
|||
### Token encryption |
|||
|
|||
https://documentation.openiddict.com/configuration/encryption-and-signing-credentials.html |
|||
|
|||
> By default, OpenIddict enforces encryption for all the token types it supports. While this enforcement cannot be disabled for authorization codes, refresh tokens and device codes for security reasons, it can be relaxed for access tokens when integration with third-party APIs/resource servers is desired. Access token encryption can also be disabled if the resource servers receiving the access tokens don't fully support JSON Web Encryption. |
|||
|
|||
```cs |
|||
PreConfigure<OpenIddictServerBuilder>(builder => |
|||
{ |
|||
builder.DisableAccessTokenEncryption(); |
|||
}); |
|||
``` |
|||
|
|||
An example of using `SecurityKey` |
|||
|
|||
> In production, it is recommended to use two RSA certificates, distinct from the certificate(s) used for HTTPS: one for encryption, one for signing. |
|||
|
|||
```cs |
|||
// In OpenIddict Server |
|||
PreConfigure<OpenIddictServerBuilder>(builder => |
|||
{ |
|||
builder.AddSigningKey(new SymmetricSecurityKey(Encoding.UTF8.GetBytes("Abp_OpenIddict_Demo_C40DBB176E78"))); |
|||
builder.AddEncryptionKey(new SymmetricSecurityKey(Encoding.UTF8.GetBytes("Abp_OpenIddict_Demo_87E33FC57D80"))); |
|||
}); |
|||
|
|||
//In Client AddJwtBearer |
|||
builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme) |
|||
.AddJwtBearer(options => |
|||
{ |
|||
//Other configuration |
|||
|
|||
options.TokenValidationParameters.IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes("Abp_OpenIddict_Demo_C40DBB176E78")); |
|||
options.TokenValidationParameters.TokenDecryptionKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes("Abp_OpenIddict_Demo_87E33FC57D80")); |
|||
}); |
|||
``` |
|||
|
|||
|
|||
### PKCE |
|||
|
|||
https://documentation.openiddict.com/configuration/proof-key-for-code-exchange.html |
|||
|
|||
### Request/Response process |
|||
|
|||
I will briefly introduce the principle of OpenIddict so that everyone can quickly understand it. |
|||
|
|||
The `OpenIddict.Server.AspNetCore` adds an authentication scheme(`Name: OpenIddict.Server.AspNetCore, handler: OpenIddictServerAspNetCoreHandler`) and implements the `IAuthenticationRequestHandler` interface. |
|||
|
|||
It will be executed first in `AuthenticationMiddleware` and can short-circuit the current request. Otherwise, `DefaultAuthenticateScheme` will be called and continue to execute the pipeline. |
|||
|
|||
`OpenIddictServerAspNetCoreHandler` will call various built-in handlers(Handling requests and responses), And the handler will process according to the context or skip logic that has nothing to do with it. |
|||
|
|||
Example a token request: |
|||
|
|||
``` |
|||
POST /connect/token HTTP/1.1 |
|||
Content-Type: application/x-www-form-urlencoded |
|||
|
|||
grant_type=password& |
|||
client_id=AbpApp& |
|||
client_secret=1q2w3e*& |
|||
username=admin& |
|||
password=1q2w3E*& |
|||
scope=AbpAPI offline_access |
|||
``` |
|||
|
|||
This request will be processed by various handlers. They will confirm the endpoint type of the request, check `http/https`, verify that the request parameters (`client. scope etc`) are valid and exist in the database, etc. Various protocol checks. And build a `OpenIddictRequest` object, If there are any errors, the response content may be set and directly short-circuit the current request. |
|||
|
|||
If everything is ok, the request will go to our processing controller(eg `TokenController`), we can get an `OpenIddictRequest` from the http request at this time. The rest of our work will be based on this object. |
|||
|
|||
We may check the `username` and `password` in the request. If it is correct we create a `ClaimsPrincipal` object and return a `SignInResult`, which uses the `OpenIddict.Validation.AspNetCore` authentication scheme name, will calls `OpenIddictServerAspNetCoreHandler` for processing. |
|||
|
|||
`OpenIddictServerAspNetCoreHandler` do some checks to generate json and replace the http response content. |
|||
|
|||
The `ForbidResult` `ChallengeResult` are all the above types of processing. |
|||
|
|||
If you need to customize OpenIddict, you need to replace/delete/add new handlers and make it execute in the correct order. |
|||
|
|||
Please refer to: |
|||
https://documentation.openiddict.com/guides/index.html#events-model |
|||
|
|||
## Sponsor |
|||
|
|||
Please consider sponsoring this project: https://github.com/sponsors/kevinchalet |
|||
@ -0,0 +1,248 @@ |
|||
# ABP CLI - 新解决方案命令示例 |
|||
|
|||
`abp new`命令基于abp模板创建abp解决方案或其他组件. [ABP CLI](CLI.md)有一些参数可以用于创建新的ABP解决方案. 在本文档中, 我们将向你展示一些创建新的解决方案的命令示例. 所有的项目名称都是`Acme.BookStore`. 目前, 唯一可用的移动端项目是`React Native`移动端应用程序. 可用的数据库提供程序有`Entity Framework Core`和`MongoDB`. 所有命令都以`abp new`开头. |
|||
|
|||
## Angular |
|||
|
|||
以下命令用于创建Angular UI项目: |
|||
|
|||
* 在新文件夹中创建项目, **Entity Framework Core**, 非移动端应用程序: |
|||
|
|||
````bash |
|||
abp new Acme.BookStore -u angular --mobile none --database-provider ef -csf |
|||
```` |
|||
|
|||
* 在新文件夹中创建项目, **Entity Framework Core**, 默认应用程序模板, **拆分Identity Server**: |
|||
|
|||
```bash |
|||
abp new Acme.BookStore -t app -u angular -m none --separate-identity-server --database-provider ef -csf |
|||
``` |
|||
|
|||
* 在新文件夹中创建项目, **Entity Framework Core**, **自定义连接字符串**: |
|||
|
|||
```bash |
|||
abp new Acme.BookStore -u angular -csf --connection-string Server=localhost;Database=MyDatabase;Trusted_Connection=True |
|||
``` |
|||
|
|||
* 在`C:\MyProjects\Acme.BookStore`中创建解决方案, **MongoDB**, 默认应用程序模板, 包含移动端项目: |
|||
|
|||
```bash |
|||
abp new Acme.BookStore -u angular --database-provider mongodb --output-folder C:\MyProjects\Acme.BookStore |
|||
``` |
|||
|
|||
* 在新文件夹中创建项目, **MongoDB**, 默认应用程序模板, 不创建移动端应用程序, **拆分Identity Server**: |
|||
|
|||
```bash |
|||
abp new Acme.BookStore -t app -u angular -m none --separate-identity-server --database-provider mongodb -csf |
|||
``` |
|||
|
|||
## MVC |
|||
|
|||
以下命令用于创建MVC UI项目: |
|||
|
|||
* 在新文件夹中创建项目, **Entity Framework Core**, 不创建移动端应用程序: |
|||
|
|||
```bash |
|||
abp new Acme.BookStore -t app -u mvc --mobile none --database-provider ef -csf |
|||
``` |
|||
|
|||
* 在新文件夹中创建项目, **Entity Framework Core**, **分层结构** (*Web和HTTP API层是分开的*), 不创建移动端应用程序: |
|||
|
|||
```bash |
|||
abp new Acme.BookStore -u mvc --mobile none --tiered --database-provider ef -csf |
|||
``` |
|||
|
|||
* 在新文件夹中创建项目, **MongoDB**, 不创建移动端应用程序: |
|||
|
|||
```bash |
|||
abp new Acme.BookStore -t app -u mvc --mobile none --database-provider mongodb -csf |
|||
``` |
|||
|
|||
* 在新文件夹中创建项目, **MongoDB**, **分层结构**: |
|||
|
|||
```bash |
|||
abp new Acme.BookStore -u mvc --tiered --database-provider mongodb -csf |
|||
``` |
|||
|
|||
|
|||
## Blazor |
|||
|
|||
以下命令用于创建Blazor项目: |
|||
|
|||
* **Entity Framework Core**, 不创建移动端应用程序: |
|||
|
|||
```bash |
|||
abp new Acme.BookStore -t app -u blazor --mobile none |
|||
``` |
|||
|
|||
* **Entity Framework Core**, **拆分Identity Server**, 包含移动端应用程序: |
|||
|
|||
```bash |
|||
abp new Acme.BookStore -u blazor --separate-identity-server |
|||
``` |
|||
|
|||
* 在新文件夹中创建项目, **MongoDB**, 不创建移动端应用程序: |
|||
|
|||
```bash |
|||
abp new Acme.BookStore -u blazor --database-provider mongodb --mobile none -csf |
|||
``` |
|||
|
|||
## Blazor Server |
|||
|
|||
以下命令用于创建Blazor项目: |
|||
|
|||
* **Entity Framework Core**, 不创建移动端应用程序: |
|||
|
|||
```bash |
|||
abp new Acme.BookStore -t app -u blazor-server --mobile none |
|||
``` |
|||
|
|||
* **Entity Framework Core**, **拆分Identity Server**, **拆分API Host**, 包含移动端应用程序: |
|||
|
|||
```bash |
|||
abp new Acme.BookStore -u blazor-server --tiered |
|||
``` |
|||
|
|||
* 在新文件夹中创建项目, **MongoDB**, 不创建移动端应用程序: |
|||
|
|||
```bash |
|||
abp new Acme.BookStore -u blazor --database-provider mongodb --mobile none -csf |
|||
``` |
|||
|
|||
## 无UI |
|||
|
|||
在默认应用程序模板中, 始终有一个前端项目. 在这个选项中没有前端项目. 它有一个`HttpApi.Host`项目为你的HTTP WebAPI提供服务. 这个选项适合在你想创建一个WebAPI服务时使用. |
|||
|
|||
* 在新文件夹中创建项目, **Entity Framework Core**, 拆分Identity Server: |
|||
|
|||
```bash |
|||
abp new Acme.BookStore -u none --separate-identity-server -csf |
|||
``` |
|||
* **MongoDB**, 不创建移动端应用程序: |
|||
|
|||
```bash |
|||
abp new Acme.BookStore -u none --mobile none --database-provider mongodb |
|||
``` |
|||
|
|||
|
|||
|
|||
## 控制台应用程序 |
|||
|
|||
这是一个基于.NET控制台应用程序的模板, 集成了ABP模块架构. 要创建控制台应用程序, 请使用以下命令: |
|||
|
|||
* 项目由以下文件组成: `Acme.BookStore.csproj`, `appsettings.json`, `BookStoreHostedService.cs`, `BookStoreModule.cs`, `HelloWorldService.cs` 和 `Program.cs`. |
|||
|
|||
```bash |
|||
abp new Acme.BookStore -t console -csf |
|||
``` |
|||
|
|||
## 模块 |
|||
|
|||
模块是主项目使用的可重用子应用程序. 如果你正在构建微服务解决方案, 使用ABP模块是最佳方案. 由于模块不是最终的应用程序, 每个模块都有前端UI项目和数据库提供程序. 模块模板带有MVC UI, 可以在没有最终解决方案的情况下进行开发. 但是, 如果要在最终解决方案下开发模块, 可以添加`--no-ui`参数来去除MVC UI项目. |
|||
|
|||
* 包含前端: `MVC`, `Angular`, `Blazor`. 包含数据库提供程序: `Entity Framework Core`, `MongoDB`. 包含MVC启动项目. |
|||
|
|||
```bash |
|||
abp new Acme.IssueManagement -t module |
|||
``` |
|||
* 与上面相同, 但不包括MVC启动项目. |
|||
|
|||
```bash |
|||
abp new Acme.IssueManagement -t module --no-ui |
|||
``` |
|||
|
|||
* 创建模块并将其添加到解决方案中 |
|||
|
|||
```bash |
|||
abp new Acme.IssueManagement -t module --add-to-solution-file |
|||
``` |
|||
|
|||
## 从特定版本创建解决方案 |
|||
|
|||
创建解决方案时, 它总是使用最新版本创建. 要从旧版本创建项目, 可以使用`--version`参数. |
|||
|
|||
* 使用v3.3.0版本创建解决方案, 包含Angular UI和Entity Framework Core. |
|||
|
|||
```bash |
|||
abp new Acme.BookStore -t app -u angular -m none --database-provider ef -csf --version 3.3.0 |
|||
``` |
|||
|
|||
要获取ABP版本列表, 请查看以下链接: https://www.nuget.org/packages/Volo.Abp.Core/ |
|||
|
|||
## 从自定义模板创建 |
|||
|
|||
ABP CLI使用默认的[应用程序模板](https://github.com/abpframework/abp/tree/dev/templates/app)创建项目. 如果要从自定义模板创建新的解决方案, 可以使用参数`--template-source`. |
|||
|
|||
* 在`c:\MyProjects\templates\app`目录中使用模板, MVC UI, Entity Framework Core, 不创建移动端应用程序. |
|||
|
|||
```bash |
|||
abp new Acme.BookStore -t app -u mvc --mobile none --database-provider ef --template-source "c:\MyProjects\templates\app" |
|||
``` |
|||
|
|||
* 除了此命令从URL `https://myabp.com/app-template.zip` 检索模板之外, 与上一个命令相同. |
|||
|
|||
```bash |
|||
abp new Acme.BookStore -t app -u mvc --mobile none --database-provider ef --template-source https://myabp.com/app-template.zip |
|||
``` |
|||
|
|||
## 创建预览版本 |
|||
|
|||
ABP CLI始终使用最新版本. 要从预览(RC)版本创建解决方案, 请添加`--preview`参数. |
|||
|
|||
* 在新文件夹中创建项目, Blazor UI, Entity Framework Core, 不创建移动端应用程序, **使用最新版本**: |
|||
|
|||
```bash |
|||
abp new Acme.BookStore -t app -u blazor --mobile none -csf --preview |
|||
``` |
|||
|
|||
## 选择数据库管理系统 |
|||
|
|||
默认的数据库管理系统是 `Entity Framework Core` / ` SQL Server`. 你可以通过使用`--database-management-system`参数选择DBMS. [可用的值](https://github.com/abpframework/abp/blob/dev/framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectBuilding/Building/DatabaseManagementSystem.cs) 包括 `SqlServer`, `MySQL`, `SQLite`, `Oracle`, `Oracle-Devart`, `PostgreSQL`. 默认值是 `SqlServer`. |
|||
|
|||
* 在新文件夹中创建项目, Angular UI, **PostgreSQL** 数据库: |
|||
|
|||
```bash |
|||
abp new Acme.BookStore -u angular --database-management-system PostgreSQL -csf |
|||
``` |
|||
|
|||
## 使用静态HTTP端口 |
|||
|
|||
ABP CLI始终为项目分配随机端口. 如果需要保留默认端口并且创建解决方案始终使用相同的HTTP端口, 请添加参数`--no-random-port`. |
|||
|
|||
* 在新文件夹中创建项目, MVC UI, Entity Framework Core, **静态端口**: |
|||
|
|||
```bash |
|||
abp new Acme.BookStore --no-random-port -csf |
|||
``` |
|||
|
|||
## 引用本地ABP框架 |
|||
|
|||
在ABP解决方案中, 默认情况下从NuGet引用ABP库. 有时, 你需要在本地将ABP库引用到你的解决方案中. 这利于调试框架本身. 本地ABP框架的根目录必须有`Volo.Abp.sln`文件. 你可以将以下目录的内容复制到你的文件系统中 |
|||
|
|||
* MVC UI, Entity Framework Core, **引用本地的ABP库**: |
|||
|
|||
本地路径必须是ABP存储库的根目录. |
|||
如果`C:\source\abp\framework\Volo.Abp.sln`是你的框架解决方案的路径, 那么你必须设置`--abp-path`参数值为`C:\source\abp`. |
|||
|
|||
```bash |
|||
abp new Acme.BookStore --local-framework-ref --abp-path C:\source\abp |
|||
``` |
|||
|
|||
**输出**: |
|||
|
|||
如下所示, 引用本地ABP框架库项目. |
|||
|
|||
```xml |
|||
<ItemGroup> |
|||
<ProjectReference Include="C:\source\abp\framework\src\Volo.Abp.Autofac\Volo.Abp.Autofac.csproj" /> |
|||
<ProjectReference Include="C:\source\abp\framework\src\Volo.Abp.AspNetCore.Serilog\Volo.Abp.AspNetCore.Serilog.csproj" /> |
|||
<ProjectReference Include="C:\source\abp\framework\src\Volo.Abp.AspNetCore.Authentication.JwtBearer\Volo.Abp.AspNetCore.Authentication.JwtBearer.csproj" /> |
|||
<ProjectReference Include="..\Acme.BookStore.Application\Acme.BookStore.Application.csproj" /> |
|||
<ProjectReference Include="..\Acme.BookStore.HttpApi\Acme.BookStore.HttpApi.csproj" /> |
|||
<ProjectReference Include="..\Acme.BookStore.EntityFrameworkCore\Acme.BookStore.EntityFrameworkCore.csproj" /> |
|||
</ItemGroup> |
|||
``` |
|||
|
|||
## 另请参阅 |
|||
|
|||
* [ABP CLI文档](CLI.md) |
|||
|
After Width: | Height: | Size: 18 KiB |
@ -0,0 +1,43 @@ |
|||
using System.Threading.Tasks; |
|||
using Microsoft.Extensions.Logging; |
|||
using Microsoft.Extensions.Logging.Abstractions; |
|||
using Volo.Abp.Cli.Utils; |
|||
using Volo.Abp.DependencyInjection; |
|||
|
|||
namespace Volo.Abp.Cli.Commands.Services; |
|||
|
|||
public class DotnetEfToolManager : ISingletonDependency |
|||
{ |
|||
public ICmdHelper CmdHelper { get; } |
|||
public ILogger<DotnetEfToolManager> Logger { get; set; } |
|||
|
|||
public DotnetEfToolManager(ICmdHelper cmdHelper) |
|||
{ |
|||
CmdHelper = cmdHelper; |
|||
|
|||
Logger = NullLogger<DotnetEfToolManager>.Instance; |
|||
} |
|||
|
|||
public async Task BeSureInstalledAsync() |
|||
{ |
|||
if (IsDotNetEfToolInstalled()) |
|||
{ |
|||
return; |
|||
} |
|||
|
|||
InstallDotnetEfTool(); |
|||
} |
|||
|
|||
private bool IsDotNetEfToolInstalled() |
|||
{ |
|||
var output = CmdHelper.RunCmdAndGetOutput("dotnet tool list -g"); |
|||
return output.Contains("dotnet-ef"); |
|||
} |
|||
|
|||
private void InstallDotnetEfTool() |
|||
{ |
|||
Logger.LogInformation("Installing dotnet-ef tool..."); |
|||
CmdHelper.RunCmd("dotnet tool install --global dotnet-ef"); |
|||
Logger.LogInformation("dotnet-ef tool is installed."); |
|||
} |
|||
} |
|||
@ -0,0 +1,111 @@ |
|||
using System; |
|||
using System.IO; |
|||
using System.Linq; |
|||
using System.Threading.Tasks; |
|||
using Microsoft.Extensions.Logging; |
|||
using Microsoft.Extensions.Logging.Abstractions; |
|||
using Volo.Abp.Cli.Utils; |
|||
using Volo.Abp.DependencyInjection; |
|||
|
|||
namespace Volo.Abp.Cli.Commands.Services; |
|||
|
|||
public class InitialMigrationCreator : ITransientDependency |
|||
{ |
|||
public ICmdHelper CmdHelper { get; } |
|||
public DotnetEfToolManager DotnetEfToolManager { get; } |
|||
public ILogger<InitialMigrationCreator> Logger { get; set; } |
|||
|
|||
public InitialMigrationCreator(ICmdHelper cmdHelper, DotnetEfToolManager dotnetEfToolManager) |
|||
{ |
|||
CmdHelper = cmdHelper; |
|||
DotnetEfToolManager = dotnetEfToolManager; |
|||
|
|||
Logger = NullLogger<InitialMigrationCreator>.Instance; |
|||
} |
|||
|
|||
public async Task<bool> CreateAsync(string targetProjectFolder, bool layeredTemplate = true) |
|||
{ |
|||
if (targetProjectFolder == null || !Directory.Exists(targetProjectFolder)) |
|||
{ |
|||
Logger.LogError($"This path doesn't exist: {targetProjectFolder}"); |
|||
return false; |
|||
} |
|||
|
|||
Logger.LogInformation("Creating initial migrations..."); |
|||
|
|||
await DotnetEfToolManager.BeSureInstalledAsync(); |
|||
|
|||
var tenantDbContextName = FindTenantDbContextName(targetProjectFolder); |
|||
var dbContextName = tenantDbContextName != null ? |
|||
FindDbContextName(targetProjectFolder) |
|||
: null; |
|||
|
|||
var migrationOutput = AddMigrationAndGetOutput(targetProjectFolder, dbContextName, "Migrations"); |
|||
var tenantMigrationOutput = tenantDbContextName != null ? |
|||
AddMigrationAndGetOutput(targetProjectFolder, tenantDbContextName, "TenantMigrations") |
|||
: null; |
|||
|
|||
var migrationSuccess = CheckMigrationOutput(migrationOutput) && CheckMigrationOutput(tenantMigrationOutput); |
|||
|
|||
if (migrationSuccess) |
|||
{ |
|||
Logger.LogInformation("Initial migrations are created."); |
|||
} |
|||
else |
|||
{ |
|||
Logger.LogError("Creating initial migrations process is failed! Details:" + Environment.NewLine |
|||
+ migrationOutput + Environment.NewLine |
|||
+ tenantMigrationOutput + Environment.NewLine); |
|||
} |
|||
|
|||
return migrationSuccess; |
|||
} |
|||
|
|||
private string FindTenantDbContextName(string projectFolder) |
|||
{ |
|||
var tenantDbContext = Directory.GetFiles(projectFolder, "*TenantMigrationsDbContext.cs", SearchOption.AllDirectories) |
|||
.FirstOrDefault() ?? |
|||
Directory.GetFiles(projectFolder, "*TenantDbContext.cs", SearchOption.AllDirectories) |
|||
.FirstOrDefault(); |
|||
|
|||
if (tenantDbContext == null) |
|||
{ |
|||
return null; |
|||
} |
|||
|
|||
return Path.GetFileName(tenantDbContext).RemovePostFix(".cs"); |
|||
} |
|||
|
|||
private string FindDbContextName(string projectFolder) |
|||
{ |
|||
var dbContext = Directory.GetFiles(projectFolder, "*MigrationsDbContext.cs", SearchOption.AllDirectories) |
|||
.FirstOrDefault(fp => !fp.EndsWith("TenantMigrationsDbContext.cs")) ?? |
|||
Directory.GetFiles(projectFolder, "*DbContext.cs", SearchOption.AllDirectories) |
|||
.FirstOrDefault(fp => !fp.EndsWith("TenantDbContext.cs")); |
|||
|
|||
if (dbContext == null) |
|||
{ |
|||
return null; |
|||
} |
|||
|
|||
return Path.GetFileName(dbContext).RemovePostFix(".cs"); |
|||
} |
|||
|
|||
private string AddMigrationAndGetOutput(string dbMigrationsFolder, string dbContext, string outputDirectory) |
|||
{ |
|||
var dbContextOption = string.IsNullOrWhiteSpace(dbContext) |
|||
? string.Empty |
|||
: $"--context {dbContext}"; |
|||
|
|||
var addMigrationCmd = $"dotnet ef migrations add Initial --output-dir {outputDirectory} {dbContextOption}"; |
|||
|
|||
return CmdHelper.RunCmdAndGetOutput(addMigrationCmd, out int exitCode, dbMigrationsFolder); |
|||
} |
|||
|
|||
private static bool CheckMigrationOutput(string output) |
|||
{ |
|||
return output == null || (output.Contains("Done.") && |
|||
output.Contains("To undo this action") && |
|||
output.Contains("ef migrations remove")); |
|||
} |
|||
} |
|||
@ -0,0 +1,8 @@ |
|||
using Volo.Abp.TestApp.Testing; |
|||
|
|||
namespace Volo.Abp.EntityFrameworkCore.Repositories; |
|||
|
|||
public class RepositoryExtensions_Tests : RepositoryExtensions_Tests<AbpEntityFrameworkCoreTestModule> |
|||
{ |
|||
|
|||
} |
|||
@ -0,0 +1,8 @@ |
|||
using Volo.Abp.TestApp.Testing; |
|||
|
|||
namespace Volo.Abp.MemoryDb.Repositories; |
|||
|
|||
public class RepositoryExtensions_Tests : RepositoryExtensions_Tests<AbpMemoryDbTestModule> |
|||
{ |
|||
|
|||
} |
|||
@ -0,0 +1,10 @@ |
|||
using Volo.Abp.TestApp.Testing; |
|||
using Xunit; |
|||
|
|||
namespace Volo.Abp.MongoDB.Repositories; |
|||
|
|||
[Collection(MongoTestCollection.Name)] |
|||
public class RepositoryExtensions_Tests : RepositoryExtensions_Tests<AbpMongoDbTestModule> |
|||
{ |
|||
|
|||
} |
|||
@ -0,0 +1,38 @@ |
|||
using System; |
|||
using System.Threading.Tasks; |
|||
using Volo.Abp.Domain.Entities; |
|||
using Volo.Abp.Domain.Repositories; |
|||
using Volo.Abp.Modularity; |
|||
using Volo.Abp.TestApp.Domain; |
|||
using Xunit; |
|||
|
|||
namespace Volo.Abp.TestApp.Testing; |
|||
|
|||
public abstract class RepositoryExtensions_Tests<TStartupModule> : TestAppTestBase<TStartupModule> |
|||
where TStartupModule : IAbpModule |
|||
{ |
|||
protected readonly IRepository<Person, Guid> PersonRepository; |
|||
|
|||
protected RepositoryExtensions_Tests() |
|||
{ |
|||
PersonRepository = GetRequiredService<IRepository<Person, Guid>>(); |
|||
} |
|||
|
|||
[Fact] |
|||
public async Task EnsureExistsAsync_Test() |
|||
{ |
|||
await WithUnitOfWorkAsync(async () => |
|||
{ |
|||
var id = Guid.NewGuid(); |
|||
await Assert.ThrowsAsync<EntityNotFoundException>(async () => |
|||
await PersonRepository.EnsureExistsAsync(Guid.NewGuid()) |
|||
); |
|||
await Assert.ThrowsAsync<EntityNotFoundException>(async () => |
|||
await PersonRepository.EnsureExistsAsync(x => x.Id == id) |
|||
); |
|||
|
|||
await PersonRepository.EnsureExistsAsync(TestDataBuilder.UserDouglasId); |
|||
await PersonRepository.EnsureExistsAsync(x => x.Id == TestDataBuilder.UserDouglasId); |
|||
}); |
|||
} |
|||
} |
|||
@ -1,27 +0,0 @@ |
|||
{ |
|||
"iisSettings": { |
|||
"windowsAuthentication": false, |
|||
"anonymousAuthentication": true, |
|||
"iisExpress": { |
|||
"applicationUrl": "http://localhost:2922/", |
|||
"sslPort": 44394 |
|||
} |
|||
}, |
|||
"profiles": { |
|||
"IIS Express": { |
|||
"commandName": "IISExpress", |
|||
"launchBrowser": true, |
|||
"environmentVariables": { |
|||
"ASPNETCORE_ENVIRONMENT": "Development" |
|||
} |
|||
}, |
|||
"Volo.Abp.Account.Web.IdentityServer": { |
|||
"commandName": "Project", |
|||
"launchBrowser": true, |
|||
"environmentVariables": { |
|||
"ASPNETCORE_ENVIRONMENT": "Development" |
|||
}, |
|||
"applicationUrl": "https://localhost:5001;http://localhost:5000" |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,29 @@ |
|||
using Microsoft.Extensions.DependencyInjection; |
|||
using Volo.Abp.Modularity; |
|||
using Volo.Abp.OpenIddict; |
|||
using Volo.Abp.VirtualFileSystem; |
|||
|
|||
namespace Volo.Abp.Account.Web; |
|||
|
|||
[DependsOn( |
|||
typeof(AbpAccountWebModule), |
|||
typeof(AbpOpenIddictAspNetCoreModule) |
|||
)] |
|||
public class AbpAccountWebOpenIddictModule : AbpModule |
|||
{ |
|||
public override void PreConfigureServices(ServiceConfigurationContext context) |
|||
{ |
|||
PreConfigure<IMvcBuilder>(mvcBuilder => |
|||
{ |
|||
mvcBuilder.AddApplicationPartIfNotExists(typeof(AbpAccountWebOpenIddictModule).Assembly); |
|||
}); |
|||
} |
|||
|
|||
public override void ConfigureServices(ServiceConfigurationContext context) |
|||
{ |
|||
Configure<AbpVirtualFileSystemOptions>(options => |
|||
{ |
|||
options.FileSets.AddEmbedded<AbpAccountWebOpenIddictModule>(); |
|||
}); |
|||
} |
|||
} |
|||
@ -0,0 +1,3 @@ |
|||
<Weavers xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="FodyWeavers.xsd"> |
|||
<ConfigureAwait ContinueOnCapturedContext="false" /> |
|||
</Weavers> |
|||
@ -0,0 +1,30 @@ |
|||
<?xml version="1.0" encoding="utf-8"?> |
|||
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"> |
|||
<!-- This file was generated by Fody. Manual changes to this file will be lost when your project is rebuilt. --> |
|||
<xs:element name="Weavers"> |
|||
<xs:complexType> |
|||
<xs:all> |
|||
<xs:element name="ConfigureAwait" minOccurs="0" maxOccurs="1"> |
|||
<xs:complexType> |
|||
<xs:attribute name="ContinueOnCapturedContext" type="xs:boolean" /> |
|||
</xs:complexType> |
|||
</xs:element> |
|||
</xs:all> |
|||
<xs:attribute name="VerifyAssembly" type="xs:boolean"> |
|||
<xs:annotation> |
|||
<xs:documentation>'true' to run assembly verification (PEVerify) on the target assembly after all weavers have been executed.</xs:documentation> |
|||
</xs:annotation> |
|||
</xs:attribute> |
|||
<xs:attribute name="VerifyIgnoreCodes" type="xs:string"> |
|||
<xs:annotation> |
|||
<xs:documentation>A comma-separated list of error codes that can be safely ignored in assembly verification.</xs:documentation> |
|||
</xs:annotation> |
|||
</xs:attribute> |
|||
<xs:attribute name="GenerateXsd" type="xs:boolean"> |
|||
<xs:annotation> |
|||
<xs:documentation>'false' to turn off automatic generation of the XML Schema file.</xs:documentation> |
|||
</xs:annotation> |
|||
</xs:attribute> |
|||
</xs:complexType> |
|||
</xs:element> |
|||
</xs:schema> |
|||
@ -0,0 +1,114 @@ |
|||
using System; |
|||
using System.Security.Claims; |
|||
using System.Threading.Tasks; |
|||
using Microsoft.AspNetCore.Authentication; |
|||
using Microsoft.Extensions.Options; |
|||
using Microsoft.AspNetCore.Identity; |
|||
using Microsoft.AspNetCore.Mvc; |
|||
using OpenIddict.Server; |
|||
using OpenIddict.Server.AspNetCore; |
|||
using Volo.Abp.DependencyInjection; |
|||
using Volo.Abp.MultiTenancy; |
|||
using Volo.Abp.OpenIddict; |
|||
|
|||
namespace Volo.Abp.Account.Web.Pages.Account; |
|||
|
|||
[ExposeServices(typeof(LoginModel))] |
|||
public class OpenIddictSupportedLoginModel : LoginModel |
|||
{ |
|||
protected AbpOpenIddictRequestHelper OpenIddictRequestHelper { get; } |
|||
public OpenIddictSupportedLoginModel( |
|||
IAuthenticationSchemeProvider schemeProvider, |
|||
IOptions<AbpAccountOptions> accountOptions, |
|||
IOptions<IdentityOptions> identityOptions, |
|||
AbpOpenIddictRequestHelper openIddictRequestHelper) |
|||
: base(schemeProvider, accountOptions, identityOptions) |
|||
{ |
|||
OpenIddictRequestHelper = openIddictRequestHelper; |
|||
} |
|||
|
|||
public async override Task<IActionResult> OnGetAsync() |
|||
{ |
|||
LoginInput = new LoginInputModel(); |
|||
|
|||
var request = await OpenIddictRequestHelper.GetFromReturnUrlAsync(ReturnUrl); |
|||
if (request?.ClientId != null) |
|||
{ |
|||
ShowCancelButton = true; |
|||
|
|||
LoginInput.UserNameOrEmailAddress = request.LoginHint; |
|||
|
|||
//TODO: Reference AspNetCore MultiTenancy module and use options to get the tenant key!
|
|||
var tenant = request.GetParameter(TenantResolverConsts.DefaultTenantKey)?.ToString(); |
|||
if (!string.IsNullOrEmpty(tenant)) |
|||
{ |
|||
CurrentTenant.Change(Guid.Parse(tenant)); |
|||
Response.Cookies.Append(TenantResolverConsts.DefaultTenantKey, tenant); |
|||
} |
|||
} |
|||
|
|||
return await base.OnGetAsync(); |
|||
} |
|||
|
|||
public async override Task<IActionResult> OnPostAsync(string action) |
|||
{ |
|||
if (action == "Cancel") |
|||
{ |
|||
var request = await OpenIddictRequestHelper.GetFromReturnUrlAsync(ReturnUrl); |
|||
|
|||
var transaction = HttpContext.GetOpenIddictServerTransaction(); |
|||
if (request?.ClientId != null && transaction != null) |
|||
{ |
|||
transaction.EndpointType = OpenIddictServerEndpointType.Authorization; |
|||
transaction.Request = request; |
|||
|
|||
var notification = new OpenIddictServerEvents.ValidateAuthorizationRequestContext(transaction); |
|||
transaction.SetProperty(typeof(OpenIddictServerEvents.ValidateAuthorizationRequestContext).FullName!, notification); |
|||
|
|||
return Forbid(OpenIddictServerAspNetCoreDefaults.AuthenticationScheme); |
|||
} |
|||
|
|||
return Redirect("~/"); |
|||
} |
|||
|
|||
return await base.OnPostAsync(action); |
|||
} |
|||
|
|||
public async override Task<IActionResult> OnPostExternalLogin(string provider) |
|||
{ |
|||
if (AccountOptions.WindowsAuthenticationSchemeName == provider) |
|||
{ |
|||
return await ProcessWindowsLoginAsync(); |
|||
} |
|||
|
|||
return await base.OnPostExternalLogin(provider); |
|||
} |
|||
|
|||
protected virtual async Task<IActionResult> ProcessWindowsLoginAsync() |
|||
{ |
|||
var result = await HttpContext.AuthenticateAsync(AccountOptions.WindowsAuthenticationSchemeName); |
|||
if (result.Succeeded) |
|||
{ |
|||
var props = new AuthenticationProperties() |
|||
{ |
|||
RedirectUri = Url.Page("./Login", pageHandler: "ExternalLoginCallback", values: new { ReturnUrl, ReturnUrlHash }), |
|||
Items = |
|||
{ |
|||
{ |
|||
"LoginProvider", AccountOptions.WindowsAuthenticationSchemeName |
|||
} |
|||
} |
|||
}; |
|||
|
|||
var id = new ClaimsIdentity(AccountOptions.WindowsAuthenticationSchemeName); |
|||
id.AddClaim(new Claim(ClaimTypes.NameIdentifier, result.Principal.FindFirstValue(ClaimTypes.PrimarySid))); |
|||
id.AddClaim(new Claim(ClaimTypes.Name, result.Principal.FindFirstValue(ClaimTypes.Name))); |
|||
|
|||
await HttpContext.SignInAsync(IdentityConstants.ExternalScheme, new ClaimsPrincipal(id), props); |
|||
|
|||
return Redirect(props.RedirectUri!); |
|||
} |
|||
|
|||
return Challenge(AccountOptions.WindowsAuthenticationSchemeName); |
|||
} |
|||
} |
|||
@ -0,0 +1,4 @@ |
|||
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers |
|||
@addTagHelper *, Volo.Abp.AspNetCore.Mvc.UI |
|||
@addTagHelper *, Volo.Abp.AspNetCore.Mvc.UI.Bootstrap |
|||
@addTagHelper *, Volo.Abp.AspNetCore.Mvc.UI.Bundling |
|||
@ -0,0 +1,34 @@ |
|||
<Project Sdk="Microsoft.NET.Sdk.Web"> |
|||
|
|||
<Import Project="..\..\..\..\configureawait.props" /> |
|||
<Import Project="..\..\..\..\common.props" /> |
|||
|
|||
<PropertyGroup> |
|||
<TargetFramework>net6.0</TargetFramework> |
|||
<AssemblyName>Volo.Abp.Account.Web.OpenIddict</AssemblyName> |
|||
<PackageId>Volo.Abp.Account.Web.OpenIddict</PackageId> |
|||
<IsPackable>true</IsPackable> |
|||
<AssetTargetFallback>$(AssetTargetFallback);portable-net45+win8+wp8+wpa81;</AssetTargetFallback> |
|||
<GenerateAssemblyConfigurationAttribute>false</GenerateAssemblyConfigurationAttribute> |
|||
<GenerateAssemblyCompanyAttribute>false</GenerateAssemblyCompanyAttribute> |
|||
<GenerateAssemblyProductAttribute>false</GenerateAssemblyProductAttribute> |
|||
<GenerateEmbeddedFilesManifest>true</GenerateEmbeddedFilesManifest> |
|||
<RootNamespace>Volo.Abp.Account.Web</RootNamespace> |
|||
<OutputType>Library</OutputType> |
|||
</PropertyGroup> |
|||
|
|||
|
|||
<ItemGroup> |
|||
<ProjectReference Include="..\..\..\openiddict\src\Volo.Abp.OpenIddict.AspNetCore\Volo.Abp.OpenIddict.AspNetCore.csproj" /> |
|||
<ProjectReference Include="..\Volo.Abp.Account.Web\Volo.Abp.Account.Web.csproj" /> |
|||
</ItemGroup> |
|||
|
|||
<ItemGroup> |
|||
<PackageReference Include="System.Security.Principal.Windows" Version="5.0.0" /> |
|||
</ItemGroup> |
|||
|
|||
<ItemGroup> |
|||
<PackageReference Include="Microsoft.Extensions.FileProviders.Embedded" Version="$(MicrosoftPackageVersion)" /> |
|||
</ItemGroup> |
|||
|
|||
</Project> |
|||
@ -0,0 +1,211 @@ |
|||
// CodeMirror, copyright (c) by Marijn Haverbeke and others
|
|||
// Distributed under an MIT license: https://codemirror.net/LICENSE
|
|||
|
|||
(function(mod) { |
|||
if (typeof exports == "object" && typeof module == "object") // CommonJS
|
|||
mod(require("../../lib/codemirror")); |
|||
else if (typeof define == "function" && define.amd) // AMD
|
|||
define(["../../lib/codemirror"], mod); |
|||
else // Plain browser env
|
|||
mod(CodeMirror); |
|||
})(function(CodeMirror) { |
|||
"use strict"; |
|||
|
|||
var noOptions = {}; |
|||
var nonWS = /[^\s\u00a0]/; |
|||
var Pos = CodeMirror.Pos, cmp = CodeMirror.cmpPos; |
|||
|
|||
function firstNonWS(str) { |
|||
var found = str.search(nonWS); |
|||
return found == -1 ? 0 : found; |
|||
} |
|||
|
|||
CodeMirror.commands.toggleComment = function(cm) { |
|||
cm.toggleComment(); |
|||
}; |
|||
|
|||
CodeMirror.defineExtension("toggleComment", function(options) { |
|||
if (!options) options = noOptions; |
|||
var cm = this; |
|||
var minLine = Infinity, ranges = this.listSelections(), mode = null; |
|||
for (var i = ranges.length - 1; i >= 0; i--) { |
|||
var from = ranges[i].from(), to = ranges[i].to(); |
|||
if (from.line >= minLine) continue; |
|||
if (to.line >= minLine) to = Pos(minLine, 0); |
|||
minLine = from.line; |
|||
if (mode == null) { |
|||
if (cm.uncomment(from, to, options)) mode = "un"; |
|||
else { cm.lineComment(from, to, options); mode = "line"; } |
|||
} else if (mode == "un") { |
|||
cm.uncomment(from, to, options); |
|||
} else { |
|||
cm.lineComment(from, to, options); |
|||
} |
|||
} |
|||
}); |
|||
|
|||
// Rough heuristic to try and detect lines that are part of multi-line string
|
|||
function probablyInsideString(cm, pos, line) { |
|||
return /\bstring\b/.test(cm.getTokenTypeAt(Pos(pos.line, 0))) && !/^[\'\"\`]/.test(line) |
|||
} |
|||
|
|||
function getMode(cm, pos) { |
|||
var mode = cm.getMode() |
|||
return mode.useInnerComments === false || !mode.innerMode ? mode : cm.getModeAt(pos) |
|||
} |
|||
|
|||
CodeMirror.defineExtension("lineComment", function(from, to, options) { |
|||
if (!options) options = noOptions; |
|||
var self = this, mode = getMode(self, from); |
|||
var firstLine = self.getLine(from.line); |
|||
if (firstLine == null || probablyInsideString(self, from, firstLine)) return; |
|||
|
|||
var commentString = options.lineComment || mode.lineComment; |
|||
if (!commentString) { |
|||
if (options.blockCommentStart || mode.blockCommentStart) { |
|||
options.fullLines = true; |
|||
self.blockComment(from, to, options); |
|||
} |
|||
return; |
|||
} |
|||
|
|||
var end = Math.min(to.ch != 0 || to.line == from.line ? to.line + 1 : to.line, self.lastLine() + 1); |
|||
var pad = options.padding == null ? " " : options.padding; |
|||
var blankLines = options.commentBlankLines || from.line == to.line; |
|||
|
|||
self.operation(function() { |
|||
if (options.indent) { |
|||
var baseString = null; |
|||
for (var i = from.line; i < end; ++i) { |
|||
var line = self.getLine(i); |
|||
var whitespace = line.slice(0, firstNonWS(line)); |
|||
if (baseString == null || baseString.length > whitespace.length) { |
|||
baseString = whitespace; |
|||
} |
|||
} |
|||
for (var i = from.line; i < end; ++i) { |
|||
var line = self.getLine(i), cut = baseString.length; |
|||
if (!blankLines && !nonWS.test(line)) continue; |
|||
if (line.slice(0, cut) != baseString) cut = firstNonWS(line); |
|||
self.replaceRange(baseString + commentString + pad, Pos(i, 0), Pos(i, cut)); |
|||
} |
|||
} else { |
|||
for (var i = from.line; i < end; ++i) { |
|||
if (blankLines || nonWS.test(self.getLine(i))) |
|||
self.replaceRange(commentString + pad, Pos(i, 0)); |
|||
} |
|||
} |
|||
}); |
|||
}); |
|||
|
|||
CodeMirror.defineExtension("blockComment", function(from, to, options) { |
|||
if (!options) options = noOptions; |
|||
var self = this, mode = getMode(self, from); |
|||
var startString = options.blockCommentStart || mode.blockCommentStart; |
|||
var endString = options.blockCommentEnd || mode.blockCommentEnd; |
|||
if (!startString || !endString) { |
|||
if ((options.lineComment || mode.lineComment) && options.fullLines != false) |
|||
self.lineComment(from, to, options); |
|||
return; |
|||
} |
|||
if (/\bcomment\b/.test(self.getTokenTypeAt(Pos(from.line, 0)))) return |
|||
|
|||
var end = Math.min(to.line, self.lastLine()); |
|||
if (end != from.line && to.ch == 0 && nonWS.test(self.getLine(end))) --end; |
|||
|
|||
var pad = options.padding == null ? " " : options.padding; |
|||
if (from.line > end) return; |
|||
|
|||
self.operation(function() { |
|||
if (options.fullLines != false) { |
|||
var lastLineHasText = nonWS.test(self.getLine(end)); |
|||
self.replaceRange(pad + endString, Pos(end)); |
|||
self.replaceRange(startString + pad, Pos(from.line, 0)); |
|||
var lead = options.blockCommentLead || mode.blockCommentLead; |
|||
if (lead != null) for (var i = from.line + 1; i <= end; ++i) |
|||
if (i != end || lastLineHasText) |
|||
self.replaceRange(lead + pad, Pos(i, 0)); |
|||
} else { |
|||
var atCursor = cmp(self.getCursor("to"), to) == 0, empty = !self.somethingSelected() |
|||
self.replaceRange(endString, to); |
|||
if (atCursor) self.setSelection(empty ? to : self.getCursor("from"), to) |
|||
self.replaceRange(startString, from); |
|||
} |
|||
}); |
|||
}); |
|||
|
|||
CodeMirror.defineExtension("uncomment", function(from, to, options) { |
|||
if (!options) options = noOptions; |
|||
var self = this, mode = getMode(self, from); |
|||
var end = Math.min(to.ch != 0 || to.line == from.line ? to.line : to.line - 1, self.lastLine()), start = Math.min(from.line, end); |
|||
|
|||
// Try finding line comments
|
|||
var lineString = options.lineComment || mode.lineComment, lines = []; |
|||
var pad = options.padding == null ? " " : options.padding, didSomething; |
|||
lineComment: { |
|||
if (!lineString) break lineComment; |
|||
for (var i = start; i <= end; ++i) { |
|||
var line = self.getLine(i); |
|||
var found = line.indexOf(lineString); |
|||
if (found > -1 && !/comment/.test(self.getTokenTypeAt(Pos(i, found + 1)))) found = -1; |
|||
if (found == -1 && nonWS.test(line)) break lineComment; |
|||
if (found > -1 && nonWS.test(line.slice(0, found))) break lineComment; |
|||
lines.push(line); |
|||
} |
|||
self.operation(function() { |
|||
for (var i = start; i <= end; ++i) { |
|||
var line = lines[i - start]; |
|||
var pos = line.indexOf(lineString), endPos = pos + lineString.length; |
|||
if (pos < 0) continue; |
|||
if (line.slice(endPos, endPos + pad.length) == pad) endPos += pad.length; |
|||
didSomething = true; |
|||
self.replaceRange("", Pos(i, pos), Pos(i, endPos)); |
|||
} |
|||
}); |
|||
if (didSomething) return true; |
|||
} |
|||
|
|||
// Try block comments
|
|||
var startString = options.blockCommentStart || mode.blockCommentStart; |
|||
var endString = options.blockCommentEnd || mode.blockCommentEnd; |
|||
if (!startString || !endString) return false; |
|||
var lead = options.blockCommentLead || mode.blockCommentLead; |
|||
var startLine = self.getLine(start), open = startLine.indexOf(startString) |
|||
if (open == -1) return false |
|||
var endLine = end == start ? startLine : self.getLine(end) |
|||
var close = endLine.indexOf(endString, end == start ? open + startString.length : 0); |
|||
var insideStart = Pos(start, open + 1), insideEnd = Pos(end, close + 1) |
|||
if (close == -1 || |
|||
!/comment/.test(self.getTokenTypeAt(insideStart)) || |
|||
!/comment/.test(self.getTokenTypeAt(insideEnd)) || |
|||
self.getRange(insideStart, insideEnd, "\n").indexOf(endString) > -1) |
|||
return false; |
|||
|
|||
// Avoid killing block comments completely outside the selection.
|
|||
// Positions of the last startString before the start of the selection, and the first endString after it.
|
|||
var lastStart = startLine.lastIndexOf(startString, from.ch); |
|||
var firstEnd = lastStart == -1 ? -1 : startLine.slice(0, from.ch).indexOf(endString, lastStart + startString.length); |
|||
if (lastStart != -1 && firstEnd != -1 && firstEnd + endString.length != from.ch) return false; |
|||
// Positions of the first endString after the end of the selection, and the last startString before it.
|
|||
firstEnd = endLine.indexOf(endString, to.ch); |
|||
var almostLastStart = endLine.slice(to.ch).lastIndexOf(startString, firstEnd - to.ch); |
|||
lastStart = (firstEnd == -1 || almostLastStart == -1) ? -1 : to.ch + almostLastStart; |
|||
if (firstEnd != -1 && lastStart != -1 && lastStart != to.ch) return false; |
|||
|
|||
self.operation(function() { |
|||
self.replaceRange("", Pos(end, close - (pad && endLine.slice(close - pad.length, close) == pad ? pad.length : 0)), |
|||
Pos(end, close + endString.length)); |
|||
var openEnd = open + startString.length; |
|||
if (pad && startLine.slice(openEnd, openEnd + pad.length) == pad) openEnd += pad.length; |
|||
self.replaceRange("", Pos(start, open), Pos(start, openEnd)); |
|||
if (lead) for (var i = start + 1; i <= end; ++i) { |
|||
var line = self.getLine(i), found = line.indexOf(lead); |
|||
if (found == -1 || nonWS.test(line.slice(0, found))) continue; |
|||
var foundEnd = found + lead.length; |
|||
if (pad && line.slice(foundEnd, foundEnd + pad.length) == pad) foundEnd += pad.length; |
|||
self.replaceRange("", Pos(i, found), Pos(i, foundEnd)); |
|||
} |
|||
}); |
|||
return true; |
|||
}); |
|||
}); |
|||
@ -0,0 +1,114 @@ |
|||
// CodeMirror, copyright (c) by Marijn Haverbeke and others
|
|||
// Distributed under an MIT license: https://codemirror.net/LICENSE
|
|||
|
|||
(function(mod) { |
|||
if (typeof exports == "object" && typeof module == "object") // CommonJS
|
|||
mod(require("../../lib/codemirror")); |
|||
else if (typeof define == "function" && define.amd) // AMD
|
|||
define(["../../lib/codemirror"], mod); |
|||
else // Plain browser env
|
|||
mod(CodeMirror); |
|||
})(function(CodeMirror) { |
|||
var nonspace = /\S/g; |
|||
var repeat = String.prototype.repeat || function (n) { return Array(n + 1).join(this); }; |
|||
function continueComment(cm) { |
|||
if (cm.getOption("disableInput")) return CodeMirror.Pass; |
|||
var ranges = cm.listSelections(), mode, inserts = []; |
|||
for (var i = 0; i < ranges.length; i++) { |
|||
var pos = ranges[i].head |
|||
if (!/\bcomment\b/.test(cm.getTokenTypeAt(pos))) return CodeMirror.Pass; |
|||
var modeHere = cm.getModeAt(pos) |
|||
if (!mode) mode = modeHere; |
|||
else if (mode != modeHere) return CodeMirror.Pass; |
|||
|
|||
var insert = null, line, found; |
|||
var blockStart = mode.blockCommentStart, lineCmt = mode.lineComment; |
|||
if (blockStart && mode.blockCommentContinue) { |
|||
line = cm.getLine(pos.line); |
|||
var end = line.lastIndexOf(mode.blockCommentEnd, pos.ch - mode.blockCommentEnd.length); |
|||
// 1. if this block comment ended
|
|||
// 2. if this is actually inside a line comment
|
|||
if (end != -1 && end == pos.ch - mode.blockCommentEnd.length || |
|||
lineCmt && (found = line.lastIndexOf(lineCmt, pos.ch - 1)) > -1 && |
|||
/\bcomment\b/.test(cm.getTokenTypeAt({line: pos.line, ch: found + 1}))) { |
|||
// ...then don't continue it
|
|||
} else if (pos.ch >= blockStart.length && |
|||
(found = line.lastIndexOf(blockStart, pos.ch - blockStart.length)) > -1 && |
|||
found > end) { |
|||
// reuse the existing leading spaces/tabs/mixed
|
|||
// or build the correct indent using CM's tab/indent options
|
|||
if (nonspaceAfter(0, line) >= found) { |
|||
insert = line.slice(0, found); |
|||
} else { |
|||
var tabSize = cm.options.tabSize, numTabs; |
|||
found = CodeMirror.countColumn(line, found, tabSize); |
|||
insert = !cm.options.indentWithTabs ? repeat.call(" ", found) : |
|||
repeat.call("\t", (numTabs = Math.floor(found / tabSize))) + |
|||
repeat.call(" ", found - tabSize * numTabs); |
|||
} |
|||
} else if ((found = line.indexOf(mode.blockCommentContinue)) > -1 && |
|||
found <= pos.ch && |
|||
found <= nonspaceAfter(0, line)) { |
|||
insert = line.slice(0, found); |
|||
} |
|||
if (insert != null) insert += mode.blockCommentContinue |
|||
} |
|||
if (insert == null && lineCmt && continueLineCommentEnabled(cm)) { |
|||
if (line == null) line = cm.getLine(pos.line); |
|||
found = line.indexOf(lineCmt); |
|||
// cursor at pos 0, line comment also at pos 0 => shift it down, don't continue
|
|||
if (!pos.ch && !found) insert = ""; |
|||
// continue only if the line starts with an optional space + line comment
|
|||
else if (found > -1 && nonspaceAfter(0, line) >= found) { |
|||
// don't continue if there's only space(s) after cursor or the end of the line
|
|||
insert = nonspaceAfter(pos.ch, line) > -1; |
|||
// but always continue if the next line starts with a line comment too
|
|||
if (!insert) { |
|||
var next = cm.getLine(pos.line + 1) || '', |
|||
nextFound = next.indexOf(lineCmt); |
|||
insert = nextFound > -1 && nonspaceAfter(0, next) >= nextFound || null; |
|||
} |
|||
if (insert) { |
|||
insert = line.slice(0, found) + lineCmt + |
|||
line.slice(found + lineCmt.length).match(/^\s*/)[0]; |
|||
} |
|||
} |
|||
} |
|||
if (insert == null) return CodeMirror.Pass; |
|||
inserts[i] = "\n" + insert; |
|||
} |
|||
|
|||
cm.operation(function() { |
|||
for (var i = ranges.length - 1; i >= 0; i--) |
|||
cm.replaceRange(inserts[i], ranges[i].from(), ranges[i].to(), "+insert"); |
|||
}); |
|||
} |
|||
|
|||
function nonspaceAfter(ch, str) { |
|||
nonspace.lastIndex = ch; |
|||
var m = nonspace.exec(str); |
|||
return m ? m.index : -1; |
|||
} |
|||
|
|||
function continueLineCommentEnabled(cm) { |
|||
var opt = cm.getOption("continueComments"); |
|||
if (opt && typeof opt == "object") |
|||
return opt.continueLineComment !== false; |
|||
return true; |
|||
} |
|||
|
|||
CodeMirror.defineOption("continueComments", null, function(cm, val, prev) { |
|||
if (prev && prev != CodeMirror.Init) |
|||
cm.removeKeyMap("continueComment"); |
|||
if (val) { |
|||
var key = "Enter"; |
|||
if (typeof val == "string") |
|||
key = val; |
|||
else if (typeof val == "object" && val.key) |
|||
key = val.key; |
|||
var map = {name: "continueComment"}; |
|||
map[key] = continueComment; |
|||
cm.addKeyMap(map); |
|||
} |
|||
}); |
|||
}); |
|||
@ -0,0 +1,32 @@ |
|||
.CodeMirror-dialog { |
|||
position: absolute; |
|||
left: 0; right: 0; |
|||
background: inherit; |
|||
z-index: 15; |
|||
padding: .1em .8em; |
|||
overflow: hidden; |
|||
color: inherit; |
|||
} |
|||
|
|||
.CodeMirror-dialog-top { |
|||
border-bottom: 1px solid #eee; |
|||
top: 0; |
|||
} |
|||
|
|||
.CodeMirror-dialog-bottom { |
|||
border-top: 1px solid #eee; |
|||
bottom: 0; |
|||
} |
|||
|
|||
.CodeMirror-dialog input { |
|||
border: none; |
|||
outline: none; |
|||
background: transparent; |
|||
width: 20em; |
|||
color: inherit; |
|||
font-family: monospace; |
|||
} |
|||
|
|||
.CodeMirror-dialog button { |
|||
font-size: 70%; |
|||
} |
|||
@ -0,0 +1,163 @@ |
|||
// CodeMirror, copyright (c) by Marijn Haverbeke and others
|
|||
// Distributed under an MIT license: https://codemirror.net/LICENSE
|
|||
|
|||
// Open simple dialogs on top of an editor. Relies on dialog.css.
|
|||
|
|||
(function(mod) { |
|||
if (typeof exports == "object" && typeof module == "object") // CommonJS
|
|||
mod(require("../../lib/codemirror")); |
|||
else if (typeof define == "function" && define.amd) // AMD
|
|||
define(["../../lib/codemirror"], mod); |
|||
else // Plain browser env
|
|||
mod(CodeMirror); |
|||
})(function(CodeMirror) { |
|||
function dialogDiv(cm, template, bottom) { |
|||
var wrap = cm.getWrapperElement(); |
|||
var dialog; |
|||
dialog = wrap.appendChild(document.createElement("div")); |
|||
if (bottom) |
|||
dialog.className = "CodeMirror-dialog CodeMirror-dialog-bottom"; |
|||
else |
|||
dialog.className = "CodeMirror-dialog CodeMirror-dialog-top"; |
|||
|
|||
if (typeof template == "string") { |
|||
dialog.innerHTML = template; |
|||
} else { // Assuming it's a detached DOM element.
|
|||
dialog.appendChild(template); |
|||
} |
|||
CodeMirror.addClass(wrap, 'dialog-opened'); |
|||
return dialog; |
|||
} |
|||
|
|||
function closeNotification(cm, newVal) { |
|||
if (cm.state.currentNotificationClose) |
|||
cm.state.currentNotificationClose(); |
|||
cm.state.currentNotificationClose = newVal; |
|||
} |
|||
|
|||
CodeMirror.defineExtension("openDialog", function(template, callback, options) { |
|||
if (!options) options = {}; |
|||
|
|||
closeNotification(this, null); |
|||
|
|||
var dialog = dialogDiv(this, template, options.bottom); |
|||
var closed = false, me = this; |
|||
function close(newVal) { |
|||
if (typeof newVal == 'string') { |
|||
inp.value = newVal; |
|||
} else { |
|||
if (closed) return; |
|||
closed = true; |
|||
CodeMirror.rmClass(dialog.parentNode, 'dialog-opened'); |
|||
dialog.parentNode.removeChild(dialog); |
|||
me.focus(); |
|||
|
|||
if (options.onClose) options.onClose(dialog); |
|||
} |
|||
} |
|||
|
|||
var inp = dialog.getElementsByTagName("input")[0], button; |
|||
if (inp) { |
|||
inp.focus(); |
|||
|
|||
if (options.value) { |
|||
inp.value = options.value; |
|||
if (options.selectValueOnOpen !== false) { |
|||
inp.select(); |
|||
} |
|||
} |
|||
|
|||
if (options.onInput) |
|||
CodeMirror.on(inp, "input", function(e) { options.onInput(e, inp.value, close);}); |
|||
if (options.onKeyUp) |
|||
CodeMirror.on(inp, "keyup", function(e) {options.onKeyUp(e, inp.value, close);}); |
|||
|
|||
CodeMirror.on(inp, "keydown", function(e) { |
|||
if (options && options.onKeyDown && options.onKeyDown(e, inp.value, close)) { return; } |
|||
if (e.keyCode == 27 || (options.closeOnEnter !== false && e.keyCode == 13)) { |
|||
inp.blur(); |
|||
CodeMirror.e_stop(e); |
|||
close(); |
|||
} |
|||
if (e.keyCode == 13) callback(inp.value, e); |
|||
}); |
|||
|
|||
if (options.closeOnBlur !== false) CodeMirror.on(dialog, "focusout", function (evt) { |
|||
if (evt.relatedTarget !== null) close(); |
|||
}); |
|||
} else if (button = dialog.getElementsByTagName("button")[0]) { |
|||
CodeMirror.on(button, "click", function() { |
|||
close(); |
|||
me.focus(); |
|||
}); |
|||
|
|||
if (options.closeOnBlur !== false) CodeMirror.on(button, "blur", close); |
|||
|
|||
button.focus(); |
|||
} |
|||
return close; |
|||
}); |
|||
|
|||
CodeMirror.defineExtension("openConfirm", function(template, callbacks, options) { |
|||
closeNotification(this, null); |
|||
var dialog = dialogDiv(this, template, options && options.bottom); |
|||
var buttons = dialog.getElementsByTagName("button"); |
|||
var closed = false, me = this, blurring = 1; |
|||
function close() { |
|||
if (closed) return; |
|||
closed = true; |
|||
CodeMirror.rmClass(dialog.parentNode, 'dialog-opened'); |
|||
dialog.parentNode.removeChild(dialog); |
|||
me.focus(); |
|||
} |
|||
buttons[0].focus(); |
|||
for (var i = 0; i < buttons.length; ++i) { |
|||
var b = buttons[i]; |
|||
(function(callback) { |
|||
CodeMirror.on(b, "click", function(e) { |
|||
CodeMirror.e_preventDefault(e); |
|||
close(); |
|||
if (callback) callback(me); |
|||
}); |
|||
})(callbacks[i]); |
|||
CodeMirror.on(b, "blur", function() { |
|||
--blurring; |
|||
setTimeout(function() { if (blurring <= 0) close(); }, 200); |
|||
}); |
|||
CodeMirror.on(b, "focus", function() { ++blurring; }); |
|||
} |
|||
}); |
|||
|
|||
/* |
|||
* openNotification |
|||
* Opens a notification, that can be closed with an optional timer |
|||
* (default 5000ms timer) and always closes on click. |
|||
* |
|||
* If a notification is opened while another is opened, it will close the |
|||
* currently opened one and open the new one immediately. |
|||
*/ |
|||
CodeMirror.defineExtension("openNotification", function(template, options) { |
|||
closeNotification(this, close); |
|||
var dialog = dialogDiv(this, template, options && options.bottom); |
|||
var closed = false, doneTimer; |
|||
var duration = options && typeof options.duration !== "undefined" ? options.duration : 5000; |
|||
|
|||
function close() { |
|||
if (closed) return; |
|||
closed = true; |
|||
clearTimeout(doneTimer); |
|||
CodeMirror.rmClass(dialog.parentNode, 'dialog-opened'); |
|||
dialog.parentNode.removeChild(dialog); |
|||
} |
|||
|
|||
CodeMirror.on(dialog, 'click', function(e) { |
|||
CodeMirror.e_preventDefault(e); |
|||
close(); |
|||
}); |
|||
|
|||
if (duration) |
|||
doneTimer = setTimeout(close, duration); |
|||
|
|||
return close; |
|||
}); |
|||
}); |
|||
@ -0,0 +1,47 @@ |
|||
// CodeMirror, copyright (c) by Marijn Haverbeke and others
|
|||
// Distributed under an MIT license: https://codemirror.net/LICENSE
|
|||
|
|||
(function(mod) { |
|||
if (typeof exports == "object" && typeof module == "object") // CommonJS
|
|||
mod(require("../../lib/codemirror")) |
|||
else if (typeof define == "function" && define.amd) // AMD
|
|||
define(["../../lib/codemirror"], mod) |
|||
else // Plain browser env
|
|||
mod(CodeMirror) |
|||
})(function(CodeMirror) { |
|||
"use strict" |
|||
|
|||
CodeMirror.defineOption("autoRefresh", false, function(cm, val) { |
|||
if (cm.state.autoRefresh) { |
|||
stopListening(cm, cm.state.autoRefresh) |
|||
cm.state.autoRefresh = null |
|||
} |
|||
if (val && cm.display.wrapper.offsetHeight == 0) |
|||
startListening(cm, cm.state.autoRefresh = {delay: val.delay || 250}) |
|||
}) |
|||
|
|||
function startListening(cm, state) { |
|||
function check() { |
|||
if (cm.display.wrapper.offsetHeight) { |
|||
stopListening(cm, state) |
|||
if (cm.display.lastWrapHeight != cm.display.wrapper.clientHeight) |
|||
cm.refresh() |
|||
} else { |
|||
state.timeout = setTimeout(check, state.delay) |
|||
} |
|||
} |
|||
state.timeout = setTimeout(check, state.delay) |
|||
state.hurry = function() { |
|||
clearTimeout(state.timeout) |
|||
state.timeout = setTimeout(check, 50) |
|||
} |
|||
CodeMirror.on(window, "mouseup", state.hurry) |
|||
CodeMirror.on(window, "keyup", state.hurry) |
|||
} |
|||
|
|||
function stopListening(_cm, state) { |
|||
clearTimeout(state.timeout) |
|||
CodeMirror.off(window, "mouseup", state.hurry) |
|||
CodeMirror.off(window, "keyup", state.hurry) |
|||
} |
|||
}); |
|||
@ -0,0 +1,6 @@ |
|||
.CodeMirror-fullscreen { |
|||
position: fixed; |
|||
top: 0; left: 0; right: 0; bottom: 0; |
|||
height: auto; |
|||
z-index: 9; |
|||
} |
|||
@ -0,0 +1,41 @@ |
|||
// CodeMirror, copyright (c) by Marijn Haverbeke and others
|
|||
// Distributed under an MIT license: https://codemirror.net/LICENSE
|
|||
|
|||
(function(mod) { |
|||
if (typeof exports == "object" && typeof module == "object") // CommonJS
|
|||
mod(require("../../lib/codemirror")); |
|||
else if (typeof define == "function" && define.amd) // AMD
|
|||
define(["../../lib/codemirror"], mod); |
|||
else // Plain browser env
|
|||
mod(CodeMirror); |
|||
})(function(CodeMirror) { |
|||
"use strict"; |
|||
|
|||
CodeMirror.defineOption("fullScreen", false, function(cm, val, old) { |
|||
if (old == CodeMirror.Init) old = false; |
|||
if (!old == !val) return; |
|||
if (val) setFullscreen(cm); |
|||
else setNormal(cm); |
|||
}); |
|||
|
|||
function setFullscreen(cm) { |
|||
var wrap = cm.getWrapperElement(); |
|||
cm.state.fullScreenRestore = {scrollTop: window.pageYOffset, scrollLeft: window.pageXOffset, |
|||
width: wrap.style.width, height: wrap.style.height}; |
|||
wrap.style.width = ""; |
|||
wrap.style.height = "auto"; |
|||
wrap.className += " CodeMirror-fullscreen"; |
|||
document.documentElement.style.overflow = "hidden"; |
|||
cm.refresh(); |
|||
} |
|||
|
|||
function setNormal(cm) { |
|||
var wrap = cm.getWrapperElement(); |
|||
wrap.className = wrap.className.replace(/\s*CodeMirror-fullscreen\b/, ""); |
|||
document.documentElement.style.overflow = ""; |
|||
var info = cm.state.fullScreenRestore; |
|||
wrap.style.width = info.width; wrap.style.height = info.height; |
|||
window.scrollTo(info.scrollLeft, info.scrollTop); |
|||
cm.refresh(); |
|||
} |
|||
}); |
|||
@ -0,0 +1,133 @@ |
|||
// CodeMirror, copyright (c) by Marijn Haverbeke and others
|
|||
// Distributed under an MIT license: https://codemirror.net/LICENSE
|
|||
|
|||
(function (mod) { |
|||
if (typeof exports == "object" && typeof module == "object") // CommonJS
|
|||
mod(require("../../lib/codemirror")); |
|||
else if (typeof define == "function" && define.amd) // AMD
|
|||
define(["../../lib/codemirror"], mod); |
|||
else // Plain browser env
|
|||
mod(CodeMirror); |
|||
})(function (CodeMirror) { |
|||
CodeMirror.defineExtension("addPanel", function (node, options) { |
|||
options = options || {}; |
|||
|
|||
if (!this.state.panels) initPanels(this); |
|||
|
|||
var info = this.state.panels; |
|||
var wrapper = info.wrapper; |
|||
var cmWrapper = this.getWrapperElement(); |
|||
var replace = options.replace instanceof Panel && !options.replace.cleared; |
|||
|
|||
if (options.after instanceof Panel && !options.after.cleared) { |
|||
wrapper.insertBefore(node, options.before.node.nextSibling); |
|||
} else if (options.before instanceof Panel && !options.before.cleared) { |
|||
wrapper.insertBefore(node, options.before.node); |
|||
} else if (replace) { |
|||
wrapper.insertBefore(node, options.replace.node); |
|||
options.replace.clear(true); |
|||
} else if (options.position == "bottom") { |
|||
wrapper.appendChild(node); |
|||
} else if (options.position == "before-bottom") { |
|||
wrapper.insertBefore(node, cmWrapper.nextSibling); |
|||
} else if (options.position == "after-top") { |
|||
wrapper.insertBefore(node, cmWrapper); |
|||
} else { |
|||
wrapper.insertBefore(node, wrapper.firstChild); |
|||
} |
|||
|
|||
var height = (options && options.height) || node.offsetHeight; |
|||
|
|||
var panel = new Panel(this, node, options, height); |
|||
info.panels.push(panel); |
|||
|
|||
this.setSize(); |
|||
if (options.stable && isAtTop(this, node)) |
|||
this.scrollTo(null, this.getScrollInfo().top + height); |
|||
|
|||
return panel; |
|||
}); |
|||
|
|||
function Panel(cm, node, options, height) { |
|||
this.cm = cm; |
|||
this.node = node; |
|||
this.options = options; |
|||
this.height = height; |
|||
this.cleared = false; |
|||
} |
|||
|
|||
/* when skipRemove is true, clear() was called from addPanel(). |
|||
* Thus removePanels() should not be called (issue 5518) */ |
|||
Panel.prototype.clear = function (skipRemove) { |
|||
if (this.cleared) return; |
|||
this.cleared = true; |
|||
var info = this.cm.state.panels; |
|||
info.panels.splice(info.panels.indexOf(this), 1); |
|||
this.cm.setSize(); |
|||
if (this.options.stable && isAtTop(this.cm, this.node)) |
|||
this.cm.scrollTo(null, this.cm.getScrollInfo().top - this.height) |
|||
info.wrapper.removeChild(this.node); |
|||
if (info.panels.length == 0 && !skipRemove) removePanels(this.cm); |
|||
}; |
|||
|
|||
Panel.prototype.changed = function () { |
|||
this.height = this.node.getBoundingClientRect().height; |
|||
this.cm.setSize(); |
|||
}; |
|||
|
|||
function initPanels(cm) { |
|||
var wrap = cm.getWrapperElement() |
|||
var style = window.getComputedStyle ? window.getComputedStyle(wrap) : wrap.currentStyle; |
|||
var height = parseInt(style.height); |
|||
var info = cm.state.panels = { |
|||
setHeight: wrap.style.height, |
|||
panels: [], |
|||
wrapper: document.createElement("div") |
|||
}; |
|||
var hasFocus = cm.hasFocus(), scrollPos = cm.getScrollInfo() |
|||
wrap.parentNode.insertBefore(info.wrapper, wrap); |
|||
info.wrapper.appendChild(wrap); |
|||
cm.scrollTo(scrollPos.left, scrollPos.top) |
|||
if (hasFocus) cm.focus(); |
|||
|
|||
cm._setSize = cm.setSize; |
|||
if (height != null) cm.setSize = function (width, newHeight) { |
|||
if (!newHeight) newHeight = info.wrapper.offsetHeight; |
|||
info.setHeight = newHeight; |
|||
if (typeof newHeight != "number") { |
|||
var px = /^(\d+\.?\d*)px$/.exec(newHeight); |
|||
if (px) { |
|||
newHeight = Number(px[1]); |
|||
} else { |
|||
info.wrapper.style.height = newHeight; |
|||
newHeight = info.wrapper.offsetHeight; |
|||
} |
|||
} |
|||
var editorheight = newHeight - info.panels |
|||
.map(function (p) { return p.node.getBoundingClientRect().height; }) |
|||
.reduce(function (a, b) { return a + b; }, 0); |
|||
cm._setSize(width, editorheight); |
|||
height = newHeight; |
|||
}; |
|||
} |
|||
|
|||
function removePanels(cm) { |
|||
var info = cm.state.panels; |
|||
cm.state.panels = null; |
|||
|
|||
var wrap = cm.getWrapperElement() |
|||
var hasFocus = cm.hasFocus(), scrollPos = cm.getScrollInfo() |
|||
info.wrapper.parentNode.replaceChild(wrap, info.wrapper); |
|||
cm.scrollTo(scrollPos.left, scrollPos.top) |
|||
if (hasFocus) cm.focus(); |
|||
wrap.style.height = info.setHeight; |
|||
cm.setSize = cm._setSize; |
|||
cm.setSize(); |
|||
} |
|||
|
|||
function isAtTop(cm, dom) { |
|||
for (var sibling = dom.nextSibling; sibling; sibling = sibling.nextSibling) |
|||
if (sibling == cm.getWrapperElement()) return true |
|||
return false |
|||
} |
|||
}); |
|||
@ -0,0 +1,78 @@ |
|||
// CodeMirror, copyright (c) by Marijn Haverbeke and others
|
|||
// Distributed under an MIT license: https://codemirror.net/LICENSE
|
|||
|
|||
(function(mod) { |
|||
if (typeof exports == "object" && typeof module == "object") // CommonJS
|
|||
mod(require("../../lib/codemirror")); |
|||
else if (typeof define == "function" && define.amd) // AMD
|
|||
define(["../../lib/codemirror"], mod); |
|||
else // Plain browser env
|
|||
mod(CodeMirror); |
|||
})(function(CodeMirror) { |
|||
CodeMirror.defineOption("placeholder", "", function(cm, val, old) { |
|||
var prev = old && old != CodeMirror.Init; |
|||
if (val && !prev) { |
|||
cm.on("blur", onBlur); |
|||
cm.on("change", onChange); |
|||
cm.on("swapDoc", onChange); |
|||
CodeMirror.on(cm.getInputField(), "compositionupdate", cm.state.placeholderCompose = function() { onComposition(cm) }) |
|||
onChange(cm); |
|||
} else if (!val && prev) { |
|||
cm.off("blur", onBlur); |
|||
cm.off("change", onChange); |
|||
cm.off("swapDoc", onChange); |
|||
CodeMirror.off(cm.getInputField(), "compositionupdate", cm.state.placeholderCompose) |
|||
clearPlaceholder(cm); |
|||
var wrapper = cm.getWrapperElement(); |
|||
wrapper.className = wrapper.className.replace(" CodeMirror-empty", ""); |
|||
} |
|||
|
|||
if (val && !cm.hasFocus()) onBlur(cm); |
|||
}); |
|||
|
|||
function clearPlaceholder(cm) { |
|||
if (cm.state.placeholder) { |
|||
cm.state.placeholder.parentNode.removeChild(cm.state.placeholder); |
|||
cm.state.placeholder = null; |
|||
} |
|||
} |
|||
function setPlaceholder(cm) { |
|||
clearPlaceholder(cm); |
|||
var elt = cm.state.placeholder = document.createElement("pre"); |
|||
elt.style.cssText = "height: 0; overflow: visible"; |
|||
elt.style.direction = cm.getOption("direction"); |
|||
elt.className = "CodeMirror-placeholder CodeMirror-line-like"; |
|||
var placeHolder = cm.getOption("placeholder") |
|||
if (typeof placeHolder == "string") placeHolder = document.createTextNode(placeHolder) |
|||
elt.appendChild(placeHolder) |
|||
cm.display.lineSpace.insertBefore(elt, cm.display.lineSpace.firstChild); |
|||
} |
|||
|
|||
function onComposition(cm) { |
|||
setTimeout(function() { |
|||
var empty = false |
|||
if (cm.lineCount() == 1) { |
|||
var input = cm.getInputField() |
|||
empty = input.nodeName == "TEXTAREA" ? !cm.getLine(0).length |
|||
: !/[^\u200b]/.test(input.querySelector(".CodeMirror-line").textContent) |
|||
} |
|||
if (empty) setPlaceholder(cm) |
|||
else clearPlaceholder(cm) |
|||
}, 20) |
|||
} |
|||
|
|||
function onBlur(cm) { |
|||
if (isEmpty(cm)) setPlaceholder(cm); |
|||
} |
|||
function onChange(cm) { |
|||
var wrapper = cm.getWrapperElement(), empty = isEmpty(cm); |
|||
wrapper.className = wrapper.className.replace(" CodeMirror-empty", "") + (empty ? " CodeMirror-empty" : ""); |
|||
|
|||
if (empty) setPlaceholder(cm); |
|||
else clearPlaceholder(cm); |
|||
} |
|||
|
|||
function isEmpty(cm) { |
|||
return (cm.lineCount() === 1) && (cm.getLine(0) === ""); |
|||
} |
|||
}); |
|||
@ -0,0 +1,51 @@ |
|||
// CodeMirror, copyright (c) by Marijn Haverbeke and others
|
|||
// Distributed under an MIT license: https://codemirror.net/LICENSE
|
|||
|
|||
(function(mod) { |
|||
if (typeof exports == "object" && typeof module == "object") // CommonJS
|
|||
mod(require("../../lib/codemirror")); |
|||
else if (typeof define == "function" && define.amd) // AMD
|
|||
define(["../../lib/codemirror"], mod); |
|||
else // Plain browser env
|
|||
mod(CodeMirror); |
|||
})(function(CodeMirror) { |
|||
"use strict"; |
|||
|
|||
CodeMirror.defineOption("rulers", false, function(cm, val) { |
|||
if (cm.state.rulerDiv) { |
|||
cm.state.rulerDiv.parentElement.removeChild(cm.state.rulerDiv) |
|||
cm.state.rulerDiv = null |
|||
cm.off("refresh", drawRulers) |
|||
} |
|||
if (val && val.length) { |
|||
cm.state.rulerDiv = cm.display.lineSpace.parentElement.insertBefore(document.createElement("div"), cm.display.lineSpace) |
|||
cm.state.rulerDiv.className = "CodeMirror-rulers" |
|||
drawRulers(cm) |
|||
cm.on("refresh", drawRulers) |
|||
} |
|||
}); |
|||
|
|||
function drawRulers(cm) { |
|||
cm.state.rulerDiv.textContent = "" |
|||
var val = cm.getOption("rulers"); |
|||
var cw = cm.defaultCharWidth(); |
|||
var left = cm.charCoords(CodeMirror.Pos(cm.firstLine(), 0), "div").left; |
|||
cm.state.rulerDiv.style.minHeight = (cm.display.scroller.offsetHeight + 30) + "px"; |
|||
for (var i = 0; i < val.length; i++) { |
|||
var elt = document.createElement("div"); |
|||
elt.className = "CodeMirror-ruler"; |
|||
var col, conf = val[i]; |
|||
if (typeof conf == "number") { |
|||
col = conf; |
|||
} else { |
|||
col = conf.column; |
|||
if (conf.className) elt.className += " " + conf.className; |
|||
if (conf.color) elt.style.borderColor = conf.color; |
|||
if (conf.lineStyle) elt.style.borderLeftStyle = conf.lineStyle; |
|||
if (conf.width) elt.style.borderLeftWidth = conf.width; |
|||
} |
|||
elt.style.left = (left + col * cw) + "px"; |
|||
cm.state.rulerDiv.appendChild(elt) |
|||
} |
|||
} |
|||
}); |
|||
@ -0,0 +1,201 @@ |
|||
// CodeMirror, copyright (c) by Marijn Haverbeke and others
|
|||
// Distributed under an MIT license: https://codemirror.net/LICENSE
|
|||
|
|||
(function(mod) { |
|||
if (typeof exports == "object" && typeof module == "object") // CommonJS
|
|||
mod(require("../../lib/codemirror")); |
|||
else if (typeof define == "function" && define.amd) // AMD
|
|||
define(["../../lib/codemirror"], mod); |
|||
else // Plain browser env
|
|||
mod(CodeMirror); |
|||
})(function(CodeMirror) { |
|||
var defaults = { |
|||
pairs: "()[]{}''\"\"", |
|||
closeBefore: ")]}'\":;>", |
|||
triples: "", |
|||
explode: "[]{}" |
|||
}; |
|||
|
|||
var Pos = CodeMirror.Pos; |
|||
|
|||
CodeMirror.defineOption("autoCloseBrackets", false, function(cm, val, old) { |
|||
if (old && old != CodeMirror.Init) { |
|||
cm.removeKeyMap(keyMap); |
|||
cm.state.closeBrackets = null; |
|||
} |
|||
if (val) { |
|||
ensureBound(getOption(val, "pairs")) |
|||
cm.state.closeBrackets = val; |
|||
cm.addKeyMap(keyMap); |
|||
} |
|||
}); |
|||
|
|||
function getOption(conf, name) { |
|||
if (name == "pairs" && typeof conf == "string") return conf; |
|||
if (typeof conf == "object" && conf[name] != null) return conf[name]; |
|||
return defaults[name]; |
|||
} |
|||
|
|||
var keyMap = {Backspace: handleBackspace, Enter: handleEnter}; |
|||
function ensureBound(chars) { |
|||
for (var i = 0; i < chars.length; i++) { |
|||
var ch = chars.charAt(i), key = "'" + ch + "'" |
|||
if (!keyMap[key]) keyMap[key] = handler(ch) |
|||
} |
|||
} |
|||
ensureBound(defaults.pairs + "`") |
|||
|
|||
function handler(ch) { |
|||
return function(cm) { return handleChar(cm, ch); }; |
|||
} |
|||
|
|||
function getConfig(cm) { |
|||
var deflt = cm.state.closeBrackets; |
|||
if (!deflt || deflt.override) return deflt; |
|||
var mode = cm.getModeAt(cm.getCursor()); |
|||
return mode.closeBrackets || deflt; |
|||
} |
|||
|
|||
function handleBackspace(cm) { |
|||
var conf = getConfig(cm); |
|||
if (!conf || cm.getOption("disableInput")) return CodeMirror.Pass; |
|||
|
|||
var pairs = getOption(conf, "pairs"); |
|||
var ranges = cm.listSelections(); |
|||
for (var i = 0; i < ranges.length; i++) { |
|||
if (!ranges[i].empty()) return CodeMirror.Pass; |
|||
var around = charsAround(cm, ranges[i].head); |
|||
if (!around || pairs.indexOf(around) % 2 != 0) return CodeMirror.Pass; |
|||
} |
|||
for (var i = ranges.length - 1; i >= 0; i--) { |
|||
var cur = ranges[i].head; |
|||
cm.replaceRange("", Pos(cur.line, cur.ch - 1), Pos(cur.line, cur.ch + 1), "+delete"); |
|||
} |
|||
} |
|||
|
|||
function handleEnter(cm) { |
|||
var conf = getConfig(cm); |
|||
var explode = conf && getOption(conf, "explode"); |
|||
if (!explode || cm.getOption("disableInput")) return CodeMirror.Pass; |
|||
|
|||
var ranges = cm.listSelections(); |
|||
for (var i = 0; i < ranges.length; i++) { |
|||
if (!ranges[i].empty()) return CodeMirror.Pass; |
|||
var around = charsAround(cm, ranges[i].head); |
|||
if (!around || explode.indexOf(around) % 2 != 0) return CodeMirror.Pass; |
|||
} |
|||
cm.operation(function() { |
|||
var linesep = cm.lineSeparator() || "\n"; |
|||
cm.replaceSelection(linesep + linesep, null); |
|||
moveSel(cm, -1) |
|||
ranges = cm.listSelections(); |
|||
for (var i = 0; i < ranges.length; i++) { |
|||
var line = ranges[i].head.line; |
|||
cm.indentLine(line, null, true); |
|||
cm.indentLine(line + 1, null, true); |
|||
} |
|||
}); |
|||
} |
|||
|
|||
function moveSel(cm, dir) { |
|||
var newRanges = [], ranges = cm.listSelections(), primary = 0 |
|||
for (var i = 0; i < ranges.length; i++) { |
|||
var range = ranges[i] |
|||
if (range.head == cm.getCursor()) primary = i |
|||
var pos = range.head.ch || dir > 0 ? {line: range.head.line, ch: range.head.ch + dir} : {line: range.head.line - 1} |
|||
newRanges.push({anchor: pos, head: pos}) |
|||
} |
|||
cm.setSelections(newRanges, primary) |
|||
} |
|||
|
|||
function contractSelection(sel) { |
|||
var inverted = CodeMirror.cmpPos(sel.anchor, sel.head) > 0; |
|||
return {anchor: new Pos(sel.anchor.line, sel.anchor.ch + (inverted ? -1 : 1)), |
|||
head: new Pos(sel.head.line, sel.head.ch + (inverted ? 1 : -1))}; |
|||
} |
|||
|
|||
function handleChar(cm, ch) { |
|||
var conf = getConfig(cm); |
|||
if (!conf || cm.getOption("disableInput")) return CodeMirror.Pass; |
|||
|
|||
var pairs = getOption(conf, "pairs"); |
|||
var pos = pairs.indexOf(ch); |
|||
if (pos == -1) return CodeMirror.Pass; |
|||
|
|||
var closeBefore = getOption(conf,"closeBefore"); |
|||
|
|||
var triples = getOption(conf, "triples"); |
|||
|
|||
var identical = pairs.charAt(pos + 1) == ch; |
|||
var ranges = cm.listSelections(); |
|||
var opening = pos % 2 == 0; |
|||
|
|||
var type; |
|||
for (var i = 0; i < ranges.length; i++) { |
|||
var range = ranges[i], cur = range.head, curType; |
|||
var next = cm.getRange(cur, Pos(cur.line, cur.ch + 1)); |
|||
if (opening && !range.empty()) { |
|||
curType = "surround"; |
|||
} else if ((identical || !opening) && next == ch) { |
|||
if (identical && stringStartsAfter(cm, cur)) |
|||
curType = "both"; |
|||
else if (triples.indexOf(ch) >= 0 && cm.getRange(cur, Pos(cur.line, cur.ch + 3)) == ch + ch + ch) |
|||
curType = "skipThree"; |
|||
else |
|||
curType = "skip"; |
|||
} else if (identical && cur.ch > 1 && triples.indexOf(ch) >= 0 && |
|||
cm.getRange(Pos(cur.line, cur.ch - 2), cur) == ch + ch) { |
|||
if (cur.ch > 2 && /\bstring/.test(cm.getTokenTypeAt(Pos(cur.line, cur.ch - 2)))) return CodeMirror.Pass; |
|||
curType = "addFour"; |
|||
} else if (identical) { |
|||
var prev = cur.ch == 0 ? " " : cm.getRange(Pos(cur.line, cur.ch - 1), cur) |
|||
if (!CodeMirror.isWordChar(next) && prev != ch && !CodeMirror.isWordChar(prev)) curType = "both"; |
|||
else return CodeMirror.Pass; |
|||
} else if (opening && (next.length === 0 || /\s/.test(next) || closeBefore.indexOf(next) > -1)) { |
|||
curType = "both"; |
|||
} else { |
|||
return CodeMirror.Pass; |
|||
} |
|||
if (!type) type = curType; |
|||
else if (type != curType) return CodeMirror.Pass; |
|||
} |
|||
|
|||
var left = pos % 2 ? pairs.charAt(pos - 1) : ch; |
|||
var right = pos % 2 ? ch : pairs.charAt(pos + 1); |
|||
cm.operation(function() { |
|||
if (type == "skip") { |
|||
moveSel(cm, 1) |
|||
} else if (type == "skipThree") { |
|||
moveSel(cm, 3) |
|||
} else if (type == "surround") { |
|||
var sels = cm.getSelections(); |
|||
for (var i = 0; i < sels.length; i++) |
|||
sels[i] = left + sels[i] + right; |
|||
cm.replaceSelections(sels, "around"); |
|||
sels = cm.listSelections().slice(); |
|||
for (var i = 0; i < sels.length; i++) |
|||
sels[i] = contractSelection(sels[i]); |
|||
cm.setSelections(sels); |
|||
} else if (type == "both") { |
|||
cm.replaceSelection(left + right, null); |
|||
cm.triggerElectric(left + right); |
|||
moveSel(cm, -1) |
|||
} else if (type == "addFour") { |
|||
cm.replaceSelection(left + left + left + left, "before"); |
|||
moveSel(cm, 1) |
|||
} |
|||
}); |
|||
} |
|||
|
|||
function charsAround(cm, pos) { |
|||
var str = cm.getRange(Pos(pos.line, pos.ch - 1), |
|||
Pos(pos.line, pos.ch + 1)); |
|||
return str.length == 2 ? str : null; |
|||
} |
|||
|
|||
function stringStartsAfter(cm, pos) { |
|||
var token = cm.getTokenAt(Pos(pos.line, pos.ch + 1)) |
|||
return /\bstring/.test(token.type) && token.start == pos.ch && |
|||
(pos.ch == 0 || !/\bstring/.test(cm.getTokenTypeAt(pos))) |
|||
} |
|||
}); |
|||
@ -0,0 +1,185 @@ |
|||
// CodeMirror, copyright (c) by Marijn Haverbeke and others
|
|||
// Distributed under an MIT license: https://codemirror.net/LICENSE
|
|||
|
|||
/** |
|||
* Tag-closer extension for CodeMirror. |
|||
* |
|||
* This extension adds an "autoCloseTags" option that can be set to |
|||
* either true to get the default behavior, or an object to further |
|||
* configure its behavior. |
|||
* |
|||
* These are supported options: |
|||
* |
|||
* `whenClosing` (default true) |
|||
* Whether to autoclose when the '/' of a closing tag is typed. |
|||
* `whenOpening` (default true) |
|||
* Whether to autoclose the tag when the final '>' of an opening |
|||
* tag is typed. |
|||
* `dontCloseTags` (default is empty tags for HTML, none for XML) |
|||
* An array of tag names that should not be autoclosed. |
|||
* `indentTags` (default is block tags for HTML, none for XML) |
|||
* An array of tag names that should, when opened, cause a |
|||
* blank line to be added inside the tag, and the blank line and |
|||
* closing line to be indented. |
|||
* `emptyTags` (default is none) |
|||
* An array of XML tag names that should be autoclosed with '/>'. |
|||
* |
|||
* See demos/closetag.html for a usage example. |
|||
*/ |
|||
|
|||
(function(mod) { |
|||
if (typeof exports == "object" && typeof module == "object") // CommonJS
|
|||
mod(require("../../lib/codemirror"), require("../fold/xml-fold")); |
|||
else if (typeof define == "function" && define.amd) // AMD
|
|||
define(["../../lib/codemirror", "../fold/xml-fold"], mod); |
|||
else // Plain browser env
|
|||
mod(CodeMirror); |
|||
})(function(CodeMirror) { |
|||
CodeMirror.defineOption("autoCloseTags", false, function(cm, val, old) { |
|||
if (old != CodeMirror.Init && old) |
|||
cm.removeKeyMap("autoCloseTags"); |
|||
if (!val) return; |
|||
var map = {name: "autoCloseTags"}; |
|||
if (typeof val != "object" || val.whenClosing !== false) |
|||
map["'/'"] = function(cm) { return autoCloseSlash(cm); }; |
|||
if (typeof val != "object" || val.whenOpening !== false) |
|||
map["'>'"] = function(cm) { return autoCloseGT(cm); }; |
|||
cm.addKeyMap(map); |
|||
}); |
|||
|
|||
var htmlDontClose = ["area", "base", "br", "col", "command", "embed", "hr", "img", "input", "keygen", "link", "meta", "param", |
|||
"source", "track", "wbr"]; |
|||
var htmlIndent = ["applet", "blockquote", "body", "button", "div", "dl", "fieldset", "form", "frameset", "h1", "h2", "h3", "h4", |
|||
"h5", "h6", "head", "html", "iframe", "layer", "legend", "object", "ol", "p", "select", "table", "ul"]; |
|||
|
|||
function autoCloseGT(cm) { |
|||
if (cm.getOption("disableInput")) return CodeMirror.Pass; |
|||
var ranges = cm.listSelections(), replacements = []; |
|||
var opt = cm.getOption("autoCloseTags"); |
|||
for (var i = 0; i < ranges.length; i++) { |
|||
if (!ranges[i].empty()) return CodeMirror.Pass; |
|||
var pos = ranges[i].head, tok = cm.getTokenAt(pos); |
|||
var inner = CodeMirror.innerMode(cm.getMode(), tok.state), state = inner.state; |
|||
var tagInfo = inner.mode.xmlCurrentTag && inner.mode.xmlCurrentTag(state) |
|||
var tagName = tagInfo && tagInfo.name |
|||
if (!tagName) return CodeMirror.Pass |
|||
|
|||
var html = inner.mode.configuration == "html"; |
|||
var dontCloseTags = (typeof opt == "object" && opt.dontCloseTags) || (html && htmlDontClose); |
|||
var indentTags = (typeof opt == "object" && opt.indentTags) || (html && htmlIndent); |
|||
|
|||
if (tok.end > pos.ch) tagName = tagName.slice(0, tagName.length - tok.end + pos.ch); |
|||
var lowerTagName = tagName.toLowerCase(); |
|||
// Don't process the '>' at the end of an end-tag or self-closing tag
|
|||
if (!tagName || |
|||
tok.type == "string" && (tok.end != pos.ch || !/[\"\']/.test(tok.string.charAt(tok.string.length - 1)) || tok.string.length == 1) || |
|||
tok.type == "tag" && tagInfo.close || |
|||
tok.string.indexOf("/") == (pos.ch - tok.start - 1) || // match something like <someTagName />
|
|||
dontCloseTags && indexOf(dontCloseTags, lowerTagName) > -1 || |
|||
closingTagExists(cm, inner.mode.xmlCurrentContext && inner.mode.xmlCurrentContext(state) || [], tagName, pos, true)) |
|||
return CodeMirror.Pass; |
|||
|
|||
var emptyTags = typeof opt == "object" && opt.emptyTags; |
|||
if (emptyTags && indexOf(emptyTags, tagName) > -1) { |
|||
replacements[i] = { text: "/>", newPos: CodeMirror.Pos(pos.line, pos.ch + 2) }; |
|||
continue; |
|||
} |
|||
|
|||
var indent = indentTags && indexOf(indentTags, lowerTagName) > -1; |
|||
replacements[i] = {indent: indent, |
|||
text: ">" + (indent ? "\n\n" : "") + "</" + tagName + ">", |
|||
newPos: indent ? CodeMirror.Pos(pos.line + 1, 0) : CodeMirror.Pos(pos.line, pos.ch + 1)}; |
|||
} |
|||
|
|||
var dontIndentOnAutoClose = (typeof opt == "object" && opt.dontIndentOnAutoClose); |
|||
for (var i = ranges.length - 1; i >= 0; i--) { |
|||
var info = replacements[i]; |
|||
cm.replaceRange(info.text, ranges[i].head, ranges[i].anchor, "+insert"); |
|||
var sel = cm.listSelections().slice(0); |
|||
sel[i] = {head: info.newPos, anchor: info.newPos}; |
|||
cm.setSelections(sel); |
|||
if (!dontIndentOnAutoClose && info.indent) { |
|||
cm.indentLine(info.newPos.line, null, true); |
|||
cm.indentLine(info.newPos.line + 1, null, true); |
|||
} |
|||
} |
|||
} |
|||
|
|||
function autoCloseCurrent(cm, typingSlash) { |
|||
var ranges = cm.listSelections(), replacements = []; |
|||
var head = typingSlash ? "/" : "</"; |
|||
var opt = cm.getOption("autoCloseTags"); |
|||
var dontIndentOnAutoClose = (typeof opt == "object" && opt.dontIndentOnSlash); |
|||
for (var i = 0; i < ranges.length; i++) { |
|||
if (!ranges[i].empty()) return CodeMirror.Pass; |
|||
var pos = ranges[i].head, tok = cm.getTokenAt(pos); |
|||
var inner = CodeMirror.innerMode(cm.getMode(), tok.state), state = inner.state; |
|||
if (typingSlash && (tok.type == "string" || tok.string.charAt(0) != "<" || |
|||
tok.start != pos.ch - 1)) |
|||
return CodeMirror.Pass; |
|||
// Kludge to get around the fact that we are not in XML mode
|
|||
// when completing in JS/CSS snippet in htmlmixed mode. Does not
|
|||
// work for other XML embedded languages (there is no general
|
|||
// way to go from a mixed mode to its current XML state).
|
|||
var replacement, mixed = inner.mode.name != "xml" && cm.getMode().name == "htmlmixed" |
|||
if (mixed && inner.mode.name == "javascript") { |
|||
replacement = head + "script"; |
|||
} else if (mixed && inner.mode.name == "css") { |
|||
replacement = head + "style"; |
|||
} else { |
|||
var context = inner.mode.xmlCurrentContext && inner.mode.xmlCurrentContext(state) |
|||
var top = context.length ? context[context.length - 1] : "" |
|||
if (!context || (context.length && closingTagExists(cm, context, top, pos))) |
|||
return CodeMirror.Pass; |
|||
replacement = head + top |
|||
} |
|||
if (cm.getLine(pos.line).charAt(tok.end) != ">") replacement += ">"; |
|||
replacements[i] = replacement; |
|||
} |
|||
cm.replaceSelections(replacements); |
|||
ranges = cm.listSelections(); |
|||
if (!dontIndentOnAutoClose) { |
|||
for (var i = 0; i < ranges.length; i++) |
|||
if (i == ranges.length - 1 || ranges[i].head.line < ranges[i + 1].head.line) |
|||
cm.indentLine(ranges[i].head.line); |
|||
} |
|||
} |
|||
|
|||
function autoCloseSlash(cm) { |
|||
if (cm.getOption("disableInput")) return CodeMirror.Pass; |
|||
return autoCloseCurrent(cm, true); |
|||
} |
|||
|
|||
CodeMirror.commands.closeTag = function(cm) { return autoCloseCurrent(cm); }; |
|||
|
|||
function indexOf(collection, elt) { |
|||
if (collection.indexOf) return collection.indexOf(elt); |
|||
for (var i = 0, e = collection.length; i < e; ++i) |
|||
if (collection[i] == elt) return i; |
|||
return -1; |
|||
} |
|||
|
|||
// If xml-fold is loaded, we use its functionality to try and verify
|
|||
// whether a given tag is actually unclosed.
|
|||
function closingTagExists(cm, context, tagName, pos, newTag) { |
|||
if (!CodeMirror.scanForClosingTag) return false; |
|||
var end = Math.min(cm.lastLine() + 1, pos.line + 500); |
|||
var nextClose = CodeMirror.scanForClosingTag(cm, pos, null, end); |
|||
if (!nextClose || nextClose.tag != tagName) return false; |
|||
// If the immediate wrapping context contains onCx instances of
|
|||
// the same tag, a closing tag only exists if there are at least
|
|||
// that many closing tags of that type following.
|
|||
var onCx = newTag ? 1 : 0 |
|||
for (var i = context.length - 1; i >= 0; i--) { |
|||
if (context[i] == tagName) ++onCx |
|||
else break |
|||
} |
|||
pos = nextClose.to; |
|||
for (var i = 1; i < onCx; i++) { |
|||
var next = CodeMirror.scanForClosingTag(cm, pos, null, end); |
|||
if (!next || next.tag != tagName) return false; |
|||
pos = next.to; |
|||
} |
|||
return true; |
|||
} |
|||
}); |
|||
@ -0,0 +1,101 @@ |
|||
// CodeMirror, copyright (c) by Marijn Haverbeke and others
|
|||
// Distributed under an MIT license: https://codemirror.net/LICENSE
|
|||
|
|||
(function(mod) { |
|||
if (typeof exports == "object" && typeof module == "object") // CommonJS
|
|||
mod(require("../../lib/codemirror")); |
|||
else if (typeof define == "function" && define.amd) // AMD
|
|||
define(["../../lib/codemirror"], mod); |
|||
else // Plain browser env
|
|||
mod(CodeMirror); |
|||
})(function(CodeMirror) { |
|||
"use strict"; |
|||
|
|||
var listRE = /^(\s*)(>[> ]*|[*+-] \[[x ]\]\s|[*+-]\s|(\d+)([.)]))(\s*)/, |
|||
emptyListRE = /^(\s*)(>[> ]*|[*+-] \[[x ]\]|[*+-]|(\d+)[.)])(\s*)$/, |
|||
unorderedListRE = /[*+-]\s/; |
|||
|
|||
CodeMirror.commands.newlineAndIndentContinueMarkdownList = function(cm) { |
|||
if (cm.getOption("disableInput")) return CodeMirror.Pass; |
|||
var ranges = cm.listSelections(), replacements = []; |
|||
for (var i = 0; i < ranges.length; i++) { |
|||
var pos = ranges[i].head; |
|||
|
|||
// If we're not in Markdown mode, fall back to normal newlineAndIndent
|
|||
var eolState = cm.getStateAfter(pos.line); |
|||
var inner = CodeMirror.innerMode(cm.getMode(), eolState); |
|||
if (inner.mode.name !== "markdown" && inner.mode.helperType !== "markdown") { |
|||
cm.execCommand("newlineAndIndent"); |
|||
return; |
|||
} else { |
|||
eolState = inner.state; |
|||
} |
|||
|
|||
var inList = eolState.list !== false; |
|||
var inQuote = eolState.quote !== 0; |
|||
|
|||
var line = cm.getLine(pos.line), match = listRE.exec(line); |
|||
var cursorBeforeBullet = /^\s*$/.test(line.slice(0, pos.ch)); |
|||
if (!ranges[i].empty() || (!inList && !inQuote) || !match || cursorBeforeBullet) { |
|||
cm.execCommand("newlineAndIndent"); |
|||
return; |
|||
} |
|||
if (emptyListRE.test(line)) { |
|||
var endOfQuote = inQuote && />\s*$/.test(line) |
|||
var endOfList = !/>\s*$/.test(line) |
|||
if (endOfQuote || endOfList) cm.replaceRange("", { |
|||
line: pos.line, ch: 0 |
|||
}, { |
|||
line: pos.line, ch: pos.ch + 1 |
|||
}); |
|||
replacements[i] = "\n"; |
|||
} else { |
|||
var indent = match[1], after = match[5]; |
|||
var numbered = !(unorderedListRE.test(match[2]) || match[2].indexOf(">") >= 0); |
|||
var bullet = numbered ? (parseInt(match[3], 10) + 1) + match[4] : match[2].replace("x", " "); |
|||
replacements[i] = "\n" + indent + bullet + after; |
|||
|
|||
if (numbered) incrementRemainingMarkdownListNumbers(cm, pos); |
|||
} |
|||
} |
|||
|
|||
cm.replaceSelections(replacements); |
|||
}; |
|||
|
|||
// Auto-updating Markdown list numbers when a new item is added to the
|
|||
// middle of a list
|
|||
function incrementRemainingMarkdownListNumbers(cm, pos) { |
|||
var startLine = pos.line, lookAhead = 0, skipCount = 0; |
|||
var startItem = listRE.exec(cm.getLine(startLine)), startIndent = startItem[1]; |
|||
|
|||
do { |
|||
lookAhead += 1; |
|||
var nextLineNumber = startLine + lookAhead; |
|||
var nextLine = cm.getLine(nextLineNumber), nextItem = listRE.exec(nextLine); |
|||
|
|||
if (nextItem) { |
|||
var nextIndent = nextItem[1]; |
|||
var newNumber = (parseInt(startItem[3], 10) + lookAhead - skipCount); |
|||
var nextNumber = (parseInt(nextItem[3], 10)), itemNumber = nextNumber; |
|||
|
|||
if (startIndent === nextIndent && !isNaN(nextNumber)) { |
|||
if (newNumber === nextNumber) itemNumber = nextNumber + 1; |
|||
if (newNumber > nextNumber) itemNumber = newNumber + 1; |
|||
cm.replaceRange( |
|||
nextLine.replace(listRE, nextIndent + itemNumber + nextItem[4] + nextItem[5]), |
|||
{ |
|||
line: nextLineNumber, ch: 0 |
|||
}, { |
|||
line: nextLineNumber, ch: nextLine.length |
|||
}); |
|||
} else { |
|||
if (startIndent.length > nextIndent.length) return; |
|||
// This doesn't run if the next line immediately indents, as it is
|
|||
// not clear of the users intention (new indented item or same level)
|
|||
if ((startIndent.length < nextIndent.length) && (lookAhead === 1)) return; |
|||
skipCount += 1; |
|||
} |
|||
} |
|||
} while (nextItem); |
|||
} |
|||
}); |
|||
@ -0,0 +1,160 @@ |
|||
// CodeMirror, copyright (c) by Marijn Haverbeke and others
|
|||
// Distributed under an MIT license: https://codemirror.net/LICENSE
|
|||
|
|||
(function(mod) { |
|||
if (typeof exports == "object" && typeof module == "object") // CommonJS
|
|||
mod(require("../../lib/codemirror")); |
|||
else if (typeof define == "function" && define.amd) // AMD
|
|||
define(["../../lib/codemirror"], mod); |
|||
else // Plain browser env
|
|||
mod(CodeMirror); |
|||
})(function(CodeMirror) { |
|||
var ie_lt8 = /MSIE \d/.test(navigator.userAgent) && |
|||
(document.documentMode == null || document.documentMode < 8); |
|||
|
|||
var Pos = CodeMirror.Pos; |
|||
|
|||
var matching = {"(": ")>", ")": "(<", "[": "]>", "]": "[<", "{": "}>", "}": "{<", "<": ">>", ">": "<<"}; |
|||
|
|||
function bracketRegex(config) { |
|||
return config && config.bracketRegex || /[(){}[\]]/ |
|||
} |
|||
|
|||
function findMatchingBracket(cm, where, config) { |
|||
var line = cm.getLineHandle(where.line), pos = where.ch - 1; |
|||
var afterCursor = config && config.afterCursor |
|||
if (afterCursor == null) |
|||
afterCursor = /(^| )cm-fat-cursor($| )/.test(cm.getWrapperElement().className) |
|||
var re = bracketRegex(config) |
|||
|
|||
// A cursor is defined as between two characters, but in in vim command mode
|
|||
// (i.e. not insert mode), the cursor is visually represented as a
|
|||
// highlighted box on top of the 2nd character. Otherwise, we allow matches
|
|||
// from before or after the cursor.
|
|||
var match = (!afterCursor && pos >= 0 && re.test(line.text.charAt(pos)) && matching[line.text.charAt(pos)]) || |
|||
re.test(line.text.charAt(pos + 1)) && matching[line.text.charAt(++pos)]; |
|||
if (!match) return null; |
|||
var dir = match.charAt(1) == ">" ? 1 : -1; |
|||
if (config && config.strict && (dir > 0) != (pos == where.ch)) return null; |
|||
var style = cm.getTokenTypeAt(Pos(where.line, pos + 1)); |
|||
|
|||
var found = scanForBracket(cm, Pos(where.line, pos + (dir > 0 ? 1 : 0)), dir, style, config); |
|||
if (found == null) return null; |
|||
return {from: Pos(where.line, pos), to: found && found.pos, |
|||
match: found && found.ch == match.charAt(0), forward: dir > 0}; |
|||
} |
|||
|
|||
// bracketRegex is used to specify which type of bracket to scan
|
|||
// should be a regexp, e.g. /[[\]]/
|
|||
//
|
|||
// Note: If "where" is on an open bracket, then this bracket is ignored.
|
|||
//
|
|||
// Returns false when no bracket was found, null when it reached
|
|||
// maxScanLines and gave up
|
|||
function scanForBracket(cm, where, dir, style, config) { |
|||
var maxScanLen = (config && config.maxScanLineLength) || 10000; |
|||
var maxScanLines = (config && config.maxScanLines) || 1000; |
|||
|
|||
var stack = []; |
|||
var re = bracketRegex(config) |
|||
var lineEnd = dir > 0 ? Math.min(where.line + maxScanLines, cm.lastLine() + 1) |
|||
: Math.max(cm.firstLine() - 1, where.line - maxScanLines); |
|||
for (var lineNo = where.line; lineNo != lineEnd; lineNo += dir) { |
|||
var line = cm.getLine(lineNo); |
|||
if (!line) continue; |
|||
var pos = dir > 0 ? 0 : line.length - 1, end = dir > 0 ? line.length : -1; |
|||
if (line.length > maxScanLen) continue; |
|||
if (lineNo == where.line) pos = where.ch - (dir < 0 ? 1 : 0); |
|||
for (; pos != end; pos += dir) { |
|||
var ch = line.charAt(pos); |
|||
if (re.test(ch) && (style === undefined || |
|||
(cm.getTokenTypeAt(Pos(lineNo, pos + 1)) || "") == (style || ""))) { |
|||
var match = matching[ch]; |
|||
if (match && (match.charAt(1) == ">") == (dir > 0)) stack.push(ch); |
|||
else if (!stack.length) return {pos: Pos(lineNo, pos), ch: ch}; |
|||
else stack.pop(); |
|||
} |
|||
} |
|||
} |
|||
return lineNo - dir == (dir > 0 ? cm.lastLine() : cm.firstLine()) ? false : null; |
|||
} |
|||
|
|||
function matchBrackets(cm, autoclear, config) { |
|||
// Disable brace matching in long lines, since it'll cause hugely slow updates
|
|||
var maxHighlightLen = cm.state.matchBrackets.maxHighlightLineLength || 1000, |
|||
highlightNonMatching = config && config.highlightNonMatching; |
|||
var marks = [], ranges = cm.listSelections(); |
|||
for (var i = 0; i < ranges.length; i++) { |
|||
var match = ranges[i].empty() && findMatchingBracket(cm, ranges[i].head, config); |
|||
if (match && (match.match || highlightNonMatching !== false) && cm.getLine(match.from.line).length <= maxHighlightLen) { |
|||
var style = match.match ? "CodeMirror-matchingbracket" : "CodeMirror-nonmatchingbracket"; |
|||
marks.push(cm.markText(match.from, Pos(match.from.line, match.from.ch + 1), {className: style})); |
|||
if (match.to && cm.getLine(match.to.line).length <= maxHighlightLen) |
|||
marks.push(cm.markText(match.to, Pos(match.to.line, match.to.ch + 1), {className: style})); |
|||
} |
|||
} |
|||
|
|||
if (marks.length) { |
|||
// Kludge to work around the IE bug from issue #1193, where text
|
|||
// input stops going to the textarea whenever this fires.
|
|||
if (ie_lt8 && cm.state.focused) cm.focus(); |
|||
|
|||
var clear = function() { |
|||
cm.operation(function() { |
|||
for (var i = 0; i < marks.length; i++) marks[i].clear(); |
|||
}); |
|||
}; |
|||
if (autoclear) setTimeout(clear, 800); |
|||
else return clear; |
|||
} |
|||
} |
|||
|
|||
function doMatchBrackets(cm) { |
|||
cm.operation(function() { |
|||
if (cm.state.matchBrackets.currentlyHighlighted) { |
|||
cm.state.matchBrackets.currentlyHighlighted(); |
|||
cm.state.matchBrackets.currentlyHighlighted = null; |
|||
} |
|||
cm.state.matchBrackets.currentlyHighlighted = matchBrackets(cm, false, cm.state.matchBrackets); |
|||
}); |
|||
} |
|||
|
|||
function clearHighlighted(cm) { |
|||
if (cm.state.matchBrackets && cm.state.matchBrackets.currentlyHighlighted) { |
|||
cm.state.matchBrackets.currentlyHighlighted(); |
|||
cm.state.matchBrackets.currentlyHighlighted = null; |
|||
} |
|||
} |
|||
|
|||
CodeMirror.defineOption("matchBrackets", false, function(cm, val, old) { |
|||
if (old && old != CodeMirror.Init) { |
|||
cm.off("cursorActivity", doMatchBrackets); |
|||
cm.off("focus", doMatchBrackets) |
|||
cm.off("blur", clearHighlighted) |
|||
clearHighlighted(cm); |
|||
} |
|||
if (val) { |
|||
cm.state.matchBrackets = typeof val == "object" ? val : {}; |
|||
cm.on("cursorActivity", doMatchBrackets); |
|||
cm.on("focus", doMatchBrackets) |
|||
cm.on("blur", clearHighlighted) |
|||
} |
|||
}); |
|||
|
|||
CodeMirror.defineExtension("matchBrackets", function() {matchBrackets(this, true);}); |
|||
CodeMirror.defineExtension("findMatchingBracket", function(pos, config, oldConfig){ |
|||
// Backwards-compatibility kludge
|
|||
if (oldConfig || typeof config == "boolean") { |
|||
if (!oldConfig) { |
|||
config = config ? {strict: true} : null |
|||
} else { |
|||
oldConfig.strict = config |
|||
config = oldConfig |
|||
} |
|||
} |
|||
return findMatchingBracket(this, pos, config) |
|||
}); |
|||
CodeMirror.defineExtension("scanForBracket", function(pos, dir, style, config){ |
|||
return scanForBracket(this, pos, dir, style, config); |
|||
}); |
|||
}); |
|||
@ -0,0 +1,66 @@ |
|||
// CodeMirror, copyright (c) by Marijn Haverbeke and others
|
|||
// Distributed under an MIT license: https://codemirror.net/LICENSE
|
|||
|
|||
(function(mod) { |
|||
if (typeof exports == "object" && typeof module == "object") // CommonJS
|
|||
mod(require("../../lib/codemirror"), require("../fold/xml-fold")); |
|||
else if (typeof define == "function" && define.amd) // AMD
|
|||
define(["../../lib/codemirror", "../fold/xml-fold"], mod); |
|||
else // Plain browser env
|
|||
mod(CodeMirror); |
|||
})(function(CodeMirror) { |
|||
"use strict"; |
|||
|
|||
CodeMirror.defineOption("matchTags", false, function(cm, val, old) { |
|||
if (old && old != CodeMirror.Init) { |
|||
cm.off("cursorActivity", doMatchTags); |
|||
cm.off("viewportChange", maybeUpdateMatch); |
|||
clear(cm); |
|||
} |
|||
if (val) { |
|||
cm.state.matchBothTags = typeof val == "object" && val.bothTags; |
|||
cm.on("cursorActivity", doMatchTags); |
|||
cm.on("viewportChange", maybeUpdateMatch); |
|||
doMatchTags(cm); |
|||
} |
|||
}); |
|||
|
|||
function clear(cm) { |
|||
if (cm.state.tagHit) cm.state.tagHit.clear(); |
|||
if (cm.state.tagOther) cm.state.tagOther.clear(); |
|||
cm.state.tagHit = cm.state.tagOther = null; |
|||
} |
|||
|
|||
function doMatchTags(cm) { |
|||
cm.state.failedTagMatch = false; |
|||
cm.operation(function() { |
|||
clear(cm); |
|||
if (cm.somethingSelected()) return; |
|||
var cur = cm.getCursor(), range = cm.getViewport(); |
|||
range.from = Math.min(range.from, cur.line); range.to = Math.max(cur.line + 1, range.to); |
|||
var match = CodeMirror.findMatchingTag(cm, cur, range); |
|||
if (!match) return; |
|||
if (cm.state.matchBothTags) { |
|||
var hit = match.at == "open" ? match.open : match.close; |
|||
if (hit) cm.state.tagHit = cm.markText(hit.from, hit.to, {className: "CodeMirror-matchingtag"}); |
|||
} |
|||
var other = match.at == "close" ? match.open : match.close; |
|||
if (other) |
|||
cm.state.tagOther = cm.markText(other.from, other.to, {className: "CodeMirror-matchingtag"}); |
|||
else |
|||
cm.state.failedTagMatch = true; |
|||
}); |
|||
} |
|||
|
|||
function maybeUpdateMatch(cm) { |
|||
if (cm.state.failedTagMatch) doMatchTags(cm); |
|||
} |
|||
|
|||
CodeMirror.commands.toMatchingTag = function(cm) { |
|||
var found = CodeMirror.findMatchingTag(cm, cm.getCursor()); |
|||
if (found) { |
|||
var other = found.at == "close" ? found.open : found.close; |
|||
if (other) cm.extendSelection(other.to, other.from); |
|||
} |
|||
}; |
|||
}); |
|||
@ -0,0 +1,27 @@ |
|||
// CodeMirror, copyright (c) by Marijn Haverbeke and others
|
|||
// Distributed under an MIT license: https://codemirror.net/LICENSE
|
|||
|
|||
(function(mod) { |
|||
if (typeof exports == "object" && typeof module == "object") // CommonJS
|
|||
mod(require("../../lib/codemirror")); |
|||
else if (typeof define == "function" && define.amd) // AMD
|
|||
define(["../../lib/codemirror"], mod); |
|||
else // Plain browser env
|
|||
mod(CodeMirror); |
|||
})(function(CodeMirror) { |
|||
CodeMirror.defineOption("showTrailingSpace", false, function(cm, val, prev) { |
|||
if (prev == CodeMirror.Init) prev = false; |
|||
if (prev && !val) |
|||
cm.removeOverlay("trailingspace"); |
|||
else if (!prev && val) |
|||
cm.addOverlay({ |
|||
token: function(stream) { |
|||
for (var l = stream.string.length, i = l; i && /\s/.test(stream.string.charAt(i - 1)); --i) {} |
|||
if (i > stream.pos) { stream.pos = i; return null; } |
|||
stream.pos = l; |
|||
return "trailingspace"; |
|||
}, |
|||
name: "trailingspace" |
|||
}); |
|||
}); |
|||
}); |
|||
@ -0,0 +1,119 @@ |
|||
// CodeMirror, copyright (c) by Marijn Haverbeke and others
|
|||
// Distributed under an MIT license: https://codemirror.net/LICENSE
|
|||
|
|||
(function(mod) { |
|||
if (typeof exports == "object" && typeof module == "object") // CommonJS
|
|||
mod(require("../../lib/codemirror")); |
|||
else if (typeof define == "function" && define.amd) // AMD
|
|||
define(["../../lib/codemirror"], mod); |
|||
else // Plain browser env
|
|||
mod(CodeMirror); |
|||
})(function(CodeMirror) { |
|||
"use strict"; |
|||
|
|||
function bracketFolding(pairs) { |
|||
return function(cm, start) { |
|||
var line = start.line, lineText = cm.getLine(line); |
|||
|
|||
function findOpening(pair) { |
|||
var tokenType; |
|||
for (var at = start.ch, pass = 0;;) { |
|||
var found = at <= 0 ? -1 : lineText.lastIndexOf(pair[0], at - 1); |
|||
if (found == -1) { |
|||
if (pass == 1) break; |
|||
pass = 1; |
|||
at = lineText.length; |
|||
continue; |
|||
} |
|||
if (pass == 1 && found < start.ch) break; |
|||
tokenType = cm.getTokenTypeAt(CodeMirror.Pos(line, found + 1)); |
|||
if (!/^(comment|string)/.test(tokenType)) return {ch: found + 1, tokenType: tokenType, pair: pair}; |
|||
at = found - 1; |
|||
} |
|||
} |
|||
|
|||
function findRange(found) { |
|||
var count = 1, lastLine = cm.lastLine(), end, startCh = found.ch, endCh |
|||
outer: for (var i = line; i <= lastLine; ++i) { |
|||
var text = cm.getLine(i), pos = i == line ? startCh : 0; |
|||
for (;;) { |
|||
var nextOpen = text.indexOf(found.pair[0], pos), nextClose = text.indexOf(found.pair[1], pos); |
|||
if (nextOpen < 0) nextOpen = text.length; |
|||
if (nextClose < 0) nextClose = text.length; |
|||
pos = Math.min(nextOpen, nextClose); |
|||
if (pos == text.length) break; |
|||
if (cm.getTokenTypeAt(CodeMirror.Pos(i, pos + 1)) == found.tokenType) { |
|||
if (pos == nextOpen) ++count; |
|||
else if (!--count) { end = i; endCh = pos; break outer; } |
|||
} |
|||
++pos; |
|||
} |
|||
} |
|||
|
|||
if (end == null || line == end) return null |
|||
return {from: CodeMirror.Pos(line, startCh), |
|||
to: CodeMirror.Pos(end, endCh)}; |
|||
} |
|||
|
|||
var found = [] |
|||
for (var i = 0; i < pairs.length; i++) { |
|||
var open = findOpening(pairs[i]) |
|||
if (open) found.push(open) |
|||
} |
|||
found.sort(function(a, b) { return a.ch - b.ch }) |
|||
for (var i = 0; i < found.length; i++) { |
|||
var range = findRange(found[i]) |
|||
if (range) return range |
|||
} |
|||
return null |
|||
} |
|||
} |
|||
|
|||
CodeMirror.registerHelper("fold", "brace", bracketFolding([["{", "}"], ["[", "]"]])); |
|||
|
|||
CodeMirror.registerHelper("fold", "brace-paren", bracketFolding([["{", "}"], ["[", "]"], ["(", ")"]])); |
|||
|
|||
CodeMirror.registerHelper("fold", "import", function(cm, start) { |
|||
function hasImport(line) { |
|||
if (line < cm.firstLine() || line > cm.lastLine()) return null; |
|||
var start = cm.getTokenAt(CodeMirror.Pos(line, 1)); |
|||
if (!/\S/.test(start.string)) start = cm.getTokenAt(CodeMirror.Pos(line, start.end + 1)); |
|||
if (start.type != "keyword" || start.string != "import") return null; |
|||
// Now find closing semicolon, return its position
|
|||
for (var i = line, e = Math.min(cm.lastLine(), line + 10); i <= e; ++i) { |
|||
var text = cm.getLine(i), semi = text.indexOf(";"); |
|||
if (semi != -1) return {startCh: start.end, end: CodeMirror.Pos(i, semi)}; |
|||
} |
|||
} |
|||
|
|||
var startLine = start.line, has = hasImport(startLine), prev; |
|||
if (!has || hasImport(startLine - 1) || ((prev = hasImport(startLine - 2)) && prev.end.line == startLine - 1)) |
|||
return null; |
|||
for (var end = has.end;;) { |
|||
var next = hasImport(end.line + 1); |
|||
if (next == null) break; |
|||
end = next.end; |
|||
} |
|||
return {from: cm.clipPos(CodeMirror.Pos(startLine, has.startCh + 1)), to: end}; |
|||
}); |
|||
|
|||
CodeMirror.registerHelper("fold", "include", function(cm, start) { |
|||
function hasInclude(line) { |
|||
if (line < cm.firstLine() || line > cm.lastLine()) return null; |
|||
var start = cm.getTokenAt(CodeMirror.Pos(line, 1)); |
|||
if (!/\S/.test(start.string)) start = cm.getTokenAt(CodeMirror.Pos(line, start.end + 1)); |
|||
if (start.type == "meta" && start.string.slice(0, 8) == "#include") return start.start + 8; |
|||
} |
|||
|
|||
var startLine = start.line, has = hasInclude(startLine); |
|||
if (has == null || hasInclude(startLine - 1) != null) return null; |
|||
for (var end = startLine;;) { |
|||
var next = hasInclude(end + 1); |
|||
if (next == null) break; |
|||
++end; |
|||
} |
|||
return {from: CodeMirror.Pos(startLine, has + 1), |
|||
to: cm.clipPos(CodeMirror.Pos(end))}; |
|||
}); |
|||
|
|||
}); |
|||
@ -0,0 +1,59 @@ |
|||
// CodeMirror, copyright (c) by Marijn Haverbeke and others
|
|||
// Distributed under an MIT license: https://codemirror.net/LICENSE
|
|||
|
|||
(function(mod) { |
|||
if (typeof exports == "object" && typeof module == "object") // CommonJS
|
|||
mod(require("../../lib/codemirror")); |
|||
else if (typeof define == "function" && define.amd) // AMD
|
|||
define(["../../lib/codemirror"], mod); |
|||
else // Plain browser env
|
|||
mod(CodeMirror); |
|||
})(function(CodeMirror) { |
|||
"use strict"; |
|||
|
|||
CodeMirror.registerGlobalHelper("fold", "comment", function(mode) { |
|||
return mode.blockCommentStart && mode.blockCommentEnd; |
|||
}, function(cm, start) { |
|||
var mode = cm.getModeAt(start), startToken = mode.blockCommentStart, endToken = mode.blockCommentEnd; |
|||
if (!startToken || !endToken) return; |
|||
var line = start.line, lineText = cm.getLine(line); |
|||
|
|||
var startCh; |
|||
for (var at = start.ch, pass = 0;;) { |
|||
var found = at <= 0 ? -1 : lineText.lastIndexOf(startToken, at - 1); |
|||
if (found == -1) { |
|||
if (pass == 1) return; |
|||
pass = 1; |
|||
at = lineText.length; |
|||
continue; |
|||
} |
|||
if (pass == 1 && found < start.ch) return; |
|||
if (/comment/.test(cm.getTokenTypeAt(CodeMirror.Pos(line, found + 1))) && |
|||
(found == 0 || lineText.slice(found - endToken.length, found) == endToken || |
|||
!/comment/.test(cm.getTokenTypeAt(CodeMirror.Pos(line, found))))) { |
|||
startCh = found + startToken.length; |
|||
break; |
|||
} |
|||
at = found - 1; |
|||
} |
|||
|
|||
var depth = 1, lastLine = cm.lastLine(), end, endCh; |
|||
outer: for (var i = line; i <= lastLine; ++i) { |
|||
var text = cm.getLine(i), pos = i == line ? startCh : 0; |
|||
for (;;) { |
|||
var nextOpen = text.indexOf(startToken, pos), nextClose = text.indexOf(endToken, pos); |
|||
if (nextOpen < 0) nextOpen = text.length; |
|||
if (nextClose < 0) nextClose = text.length; |
|||
pos = Math.min(nextOpen, nextClose); |
|||
if (pos == text.length) break; |
|||
if (pos == nextOpen) ++depth; |
|||
else if (!--depth) { end = i; endCh = pos; break outer; } |
|||
++pos; |
|||
} |
|||
} |
|||
if (end == null || line == end && endCh == startCh) return; |
|||
return {from: CodeMirror.Pos(line, startCh), |
|||
to: CodeMirror.Pos(end, endCh)}; |
|||
}); |
|||
|
|||
}); |
|||
@ -0,0 +1,159 @@ |
|||
// CodeMirror, copyright (c) by Marijn Haverbeke and others
|
|||
// Distributed under an MIT license: https://codemirror.net/LICENSE
|
|||
|
|||
(function(mod) { |
|||
if (typeof exports == "object" && typeof module == "object") // CommonJS
|
|||
mod(require("../../lib/codemirror")); |
|||
else if (typeof define == "function" && define.amd) // AMD
|
|||
define(["../../lib/codemirror"], mod); |
|||
else // Plain browser env
|
|||
mod(CodeMirror); |
|||
})(function(CodeMirror) { |
|||
"use strict"; |
|||
|
|||
function doFold(cm, pos, options, force) { |
|||
if (options && options.call) { |
|||
var finder = options; |
|||
options = null; |
|||
} else { |
|||
var finder = getOption(cm, options, "rangeFinder"); |
|||
} |
|||
if (typeof pos == "number") pos = CodeMirror.Pos(pos, 0); |
|||
var minSize = getOption(cm, options, "minFoldSize"); |
|||
|
|||
function getRange(allowFolded) { |
|||
var range = finder(cm, pos); |
|||
if (!range || range.to.line - range.from.line < minSize) return null; |
|||
if (force === "fold") return range; |
|||
|
|||
var marks = cm.findMarksAt(range.from); |
|||
for (var i = 0; i < marks.length; ++i) { |
|||
if (marks[i].__isFold) { |
|||
if (!allowFolded) return null; |
|||
range.cleared = true; |
|||
marks[i].clear(); |
|||
} |
|||
} |
|||
return range; |
|||
} |
|||
|
|||
var range = getRange(true); |
|||
if (getOption(cm, options, "scanUp")) while (!range && pos.line > cm.firstLine()) { |
|||
pos = CodeMirror.Pos(pos.line - 1, 0); |
|||
range = getRange(false); |
|||
} |
|||
if (!range || range.cleared || force === "unfold") return; |
|||
|
|||
var myWidget = makeWidget(cm, options, range); |
|||
CodeMirror.on(myWidget, "mousedown", function(e) { |
|||
myRange.clear(); |
|||
CodeMirror.e_preventDefault(e); |
|||
}); |
|||
var myRange = cm.markText(range.from, range.to, { |
|||
replacedWith: myWidget, |
|||
clearOnEnter: getOption(cm, options, "clearOnEnter"), |
|||
__isFold: true |
|||
}); |
|||
myRange.on("clear", function(from, to) { |
|||
CodeMirror.signal(cm, "unfold", cm, from, to); |
|||
}); |
|||
CodeMirror.signal(cm, "fold", cm, range.from, range.to); |
|||
} |
|||
|
|||
function makeWidget(cm, options, range) { |
|||
var widget = getOption(cm, options, "widget"); |
|||
|
|||
if (typeof widget == "function") { |
|||
widget = widget(range.from, range.to); |
|||
} |
|||
|
|||
if (typeof widget == "string") { |
|||
var text = document.createTextNode(widget); |
|||
widget = document.createElement("span"); |
|||
widget.appendChild(text); |
|||
widget.className = "CodeMirror-foldmarker"; |
|||
} else if (widget) { |
|||
widget = widget.cloneNode(true) |
|||
} |
|||
return widget; |
|||
} |
|||
|
|||
// Clumsy backwards-compatible interface
|
|||
CodeMirror.newFoldFunction = function(rangeFinder, widget) { |
|||
return function(cm, pos) { doFold(cm, pos, {rangeFinder: rangeFinder, widget: widget}); }; |
|||
}; |
|||
|
|||
// New-style interface
|
|||
CodeMirror.defineExtension("foldCode", function(pos, options, force) { |
|||
doFold(this, pos, options, force); |
|||
}); |
|||
|
|||
CodeMirror.defineExtension("isFolded", function(pos) { |
|||
var marks = this.findMarksAt(pos); |
|||
for (var i = 0; i < marks.length; ++i) |
|||
if (marks[i].__isFold) return true; |
|||
}); |
|||
|
|||
CodeMirror.commands.toggleFold = function(cm) { |
|||
cm.foldCode(cm.getCursor()); |
|||
}; |
|||
CodeMirror.commands.fold = function(cm) { |
|||
cm.foldCode(cm.getCursor(), null, "fold"); |
|||
}; |
|||
CodeMirror.commands.unfold = function(cm) { |
|||
cm.foldCode(cm.getCursor(), { scanUp: false }, "unfold"); |
|||
}; |
|||
CodeMirror.commands.foldAll = function(cm) { |
|||
cm.operation(function() { |
|||
for (var i = cm.firstLine(), e = cm.lastLine(); i <= e; i++) |
|||
cm.foldCode(CodeMirror.Pos(i, 0), { scanUp: false }, "fold"); |
|||
}); |
|||
}; |
|||
CodeMirror.commands.unfoldAll = function(cm) { |
|||
cm.operation(function() { |
|||
for (var i = cm.firstLine(), e = cm.lastLine(); i <= e; i++) |
|||
cm.foldCode(CodeMirror.Pos(i, 0), { scanUp: false }, "unfold"); |
|||
}); |
|||
}; |
|||
|
|||
CodeMirror.registerHelper("fold", "combine", function() { |
|||
var funcs = Array.prototype.slice.call(arguments, 0); |
|||
return function(cm, start) { |
|||
for (var i = 0; i < funcs.length; ++i) { |
|||
var found = funcs[i](cm, start); |
|||
if (found) return found; |
|||
} |
|||
}; |
|||
}); |
|||
|
|||
CodeMirror.registerHelper("fold", "auto", function(cm, start) { |
|||
var helpers = cm.getHelpers(start, "fold"); |
|||
for (var i = 0; i < helpers.length; i++) { |
|||
var cur = helpers[i](cm, start); |
|||
if (cur) return cur; |
|||
} |
|||
}); |
|||
|
|||
var defaultOptions = { |
|||
rangeFinder: CodeMirror.fold.auto, |
|||
widget: "\u2194", |
|||
minFoldSize: 0, |
|||
scanUp: false, |
|||
clearOnEnter: true |
|||
}; |
|||
|
|||
CodeMirror.defineOption("foldOptions", null); |
|||
|
|||
function getOption(cm, options, name) { |
|||
if (options && options[name] !== undefined) |
|||
return options[name]; |
|||
var editorOptions = cm.options.foldOptions; |
|||
if (editorOptions && editorOptions[name] !== undefined) |
|||
return editorOptions[name]; |
|||
return defaultOptions[name]; |
|||
} |
|||
|
|||
CodeMirror.defineExtension("foldOption", function(options, name) { |
|||
return getOption(this, options, name); |
|||
}); |
|||
}); |
|||
@ -0,0 +1,20 @@ |
|||
.CodeMirror-foldmarker { |
|||
color: blue; |
|||
text-shadow: #b9f 1px 1px 2px, #b9f -1px -1px 2px, #b9f 1px -1px 2px, #b9f -1px 1px 2px; |
|||
font-family: arial; |
|||
line-height: .3; |
|||
cursor: pointer; |
|||
} |
|||
.CodeMirror-foldgutter { |
|||
width: .7em; |
|||
} |
|||
.CodeMirror-foldgutter-open, |
|||
.CodeMirror-foldgutter-folded { |
|||
cursor: pointer; |
|||
} |
|||
.CodeMirror-foldgutter-open:after { |
|||
content: "\25BE"; |
|||
} |
|||
.CodeMirror-foldgutter-folded:after { |
|||
content: "\25B8"; |
|||
} |
|||
@ -0,0 +1,163 @@ |
|||
// CodeMirror, copyright (c) by Marijn Haverbeke and others
|
|||
// Distributed under an MIT license: https://codemirror.net/LICENSE
|
|||
|
|||
(function(mod) { |
|||
if (typeof exports == "object" && typeof module == "object") // CommonJS
|
|||
mod(require("../../lib/codemirror"), require("./foldcode")); |
|||
else if (typeof define == "function" && define.amd) // AMD
|
|||
define(["../../lib/codemirror", "./foldcode"], mod); |
|||
else // Plain browser env
|
|||
mod(CodeMirror); |
|||
})(function(CodeMirror) { |
|||
"use strict"; |
|||
|
|||
CodeMirror.defineOption("foldGutter", false, function(cm, val, old) { |
|||
if (old && old != CodeMirror.Init) { |
|||
cm.clearGutter(cm.state.foldGutter.options.gutter); |
|||
cm.state.foldGutter = null; |
|||
cm.off("gutterClick", onGutterClick); |
|||
cm.off("changes", onChange); |
|||
cm.off("viewportChange", onViewportChange); |
|||
cm.off("fold", onFold); |
|||
cm.off("unfold", onFold); |
|||
cm.off("swapDoc", onChange); |
|||
} |
|||
if (val) { |
|||
cm.state.foldGutter = new State(parseOptions(val)); |
|||
updateInViewport(cm); |
|||
cm.on("gutterClick", onGutterClick); |
|||
cm.on("changes", onChange); |
|||
cm.on("viewportChange", onViewportChange); |
|||
cm.on("fold", onFold); |
|||
cm.on("unfold", onFold); |
|||
cm.on("swapDoc", onChange); |
|||
} |
|||
}); |
|||
|
|||
var Pos = CodeMirror.Pos; |
|||
|
|||
function State(options) { |
|||
this.options = options; |
|||
this.from = this.to = 0; |
|||
} |
|||
|
|||
function parseOptions(opts) { |
|||
if (opts === true) opts = {}; |
|||
if (opts.gutter == null) opts.gutter = "CodeMirror-foldgutter"; |
|||
if (opts.indicatorOpen == null) opts.indicatorOpen = "CodeMirror-foldgutter-open"; |
|||
if (opts.indicatorFolded == null) opts.indicatorFolded = "CodeMirror-foldgutter-folded"; |
|||
return opts; |
|||
} |
|||
|
|||
function isFolded(cm, line) { |
|||
var marks = cm.findMarks(Pos(line, 0), Pos(line + 1, 0)); |
|||
for (var i = 0; i < marks.length; ++i) { |
|||
if (marks[i].__isFold) { |
|||
var fromPos = marks[i].find(-1); |
|||
if (fromPos && fromPos.line === line) |
|||
return marks[i]; |
|||
} |
|||
} |
|||
} |
|||
|
|||
function marker(spec) { |
|||
if (typeof spec == "string") { |
|||
var elt = document.createElement("div"); |
|||
elt.className = spec + " CodeMirror-guttermarker-subtle"; |
|||
return elt; |
|||
} else { |
|||
return spec.cloneNode(true); |
|||
} |
|||
} |
|||
|
|||
function updateFoldInfo(cm, from, to) { |
|||
var opts = cm.state.foldGutter.options, cur = from - 1; |
|||
var minSize = cm.foldOption(opts, "minFoldSize"); |
|||
var func = cm.foldOption(opts, "rangeFinder"); |
|||
// we can reuse the built-in indicator element if its className matches the new state
|
|||
var clsFolded = typeof opts.indicatorFolded == "string" && classTest(opts.indicatorFolded); |
|||
var clsOpen = typeof opts.indicatorOpen == "string" && classTest(opts.indicatorOpen); |
|||
cm.eachLine(from, to, function(line) { |
|||
++cur; |
|||
var mark = null; |
|||
var old = line.gutterMarkers; |
|||
if (old) old = old[opts.gutter]; |
|||
if (isFolded(cm, cur)) { |
|||
if (clsFolded && old && clsFolded.test(old.className)) return; |
|||
mark = marker(opts.indicatorFolded); |
|||
} else { |
|||
var pos = Pos(cur, 0); |
|||
var range = func && func(cm, pos); |
|||
if (range && range.to.line - range.from.line >= minSize) { |
|||
if (clsOpen && old && clsOpen.test(old.className)) return; |
|||
mark = marker(opts.indicatorOpen); |
|||
} |
|||
} |
|||
if (!mark && !old) return; |
|||
cm.setGutterMarker(line, opts.gutter, mark); |
|||
}); |
|||
} |
|||
|
|||
// copied from CodeMirror/src/util/dom.js
|
|||
function classTest(cls) { return new RegExp("(^|\\s)" + cls + "(?:$|\\s)\\s*") } |
|||
|
|||
function updateInViewport(cm) { |
|||
var vp = cm.getViewport(), state = cm.state.foldGutter; |
|||
if (!state) return; |
|||
cm.operation(function() { |
|||
updateFoldInfo(cm, vp.from, vp.to); |
|||
}); |
|||
state.from = vp.from; state.to = vp.to; |
|||
} |
|||
|
|||
function onGutterClick(cm, line, gutter) { |
|||
var state = cm.state.foldGutter; |
|||
if (!state) return; |
|||
var opts = state.options; |
|||
if (gutter != opts.gutter) return; |
|||
var folded = isFolded(cm, line); |
|||
if (folded) folded.clear(); |
|||
else cm.foldCode(Pos(line, 0), opts); |
|||
} |
|||
|
|||
function onChange(cm) { |
|||
var state = cm.state.foldGutter; |
|||
if (!state) return; |
|||
var opts = state.options; |
|||
state.from = state.to = 0; |
|||
clearTimeout(state.changeUpdate); |
|||
state.changeUpdate = setTimeout(function() { updateInViewport(cm); }, opts.foldOnChangeTimeSpan || 600); |
|||
} |
|||
|
|||
function onViewportChange(cm) { |
|||
var state = cm.state.foldGutter; |
|||
if (!state) return; |
|||
var opts = state.options; |
|||
clearTimeout(state.changeUpdate); |
|||
state.changeUpdate = setTimeout(function() { |
|||
var vp = cm.getViewport(); |
|||
if (state.from == state.to || vp.from - state.to > 20 || state.from - vp.to > 20) { |
|||
updateInViewport(cm); |
|||
} else { |
|||
cm.operation(function() { |
|||
if (vp.from < state.from) { |
|||
updateFoldInfo(cm, vp.from, state.from); |
|||
state.from = vp.from; |
|||
} |
|||
if (vp.to > state.to) { |
|||
updateFoldInfo(cm, state.to, vp.to); |
|||
state.to = vp.to; |
|||
} |
|||
}); |
|||
} |
|||
}, opts.updateViewportTimeSpan || 400); |
|||
} |
|||
|
|||
function onFold(cm, from) { |
|||
var state = cm.state.foldGutter; |
|||
if (!state) return; |
|||
var line = from.line; |
|||
if (line >= state.from && line < state.to) |
|||
updateFoldInfo(cm, line, line + 1); |
|||
} |
|||
}); |
|||
@ -0,0 +1,48 @@ |
|||
// CodeMirror, copyright (c) by Marijn Haverbeke and others
|
|||
// Distributed under an MIT license: https://codemirror.net/LICENSE
|
|||
|
|||
(function(mod) { |
|||
if (typeof exports == "object" && typeof module == "object") // CommonJS
|
|||
mod(require("../../lib/codemirror")); |
|||
else if (typeof define == "function" && define.amd) // AMD
|
|||
define(["../../lib/codemirror"], mod); |
|||
else // Plain browser env
|
|||
mod(CodeMirror); |
|||
})(function(CodeMirror) { |
|||
"use strict"; |
|||
|
|||
function lineIndent(cm, lineNo) { |
|||
var text = cm.getLine(lineNo) |
|||
var spaceTo = text.search(/\S/) |
|||
if (spaceTo == -1 || /\bcomment\b/.test(cm.getTokenTypeAt(CodeMirror.Pos(lineNo, spaceTo + 1)))) |
|||
return -1 |
|||
return CodeMirror.countColumn(text, null, cm.getOption("tabSize")) |
|||
} |
|||
|
|||
CodeMirror.registerHelper("fold", "indent", function(cm, start) { |
|||
var myIndent = lineIndent(cm, start.line) |
|||
if (myIndent < 0) return |
|||
var lastLineInFold = null |
|||
|
|||
// Go through lines until we find a line that definitely doesn't belong in
|
|||
// the block we're folding, or to the end.
|
|||
for (var i = start.line + 1, end = cm.lastLine(); i <= end; ++i) { |
|||
var indent = lineIndent(cm, i) |
|||
if (indent == -1) { |
|||
} else if (indent > myIndent) { |
|||
// Lines with a greater indent are considered part of the block.
|
|||
lastLineInFold = i; |
|||
} else { |
|||
// If this line has non-space, non-comment content, and is
|
|||
// indented less or equal to the start line, it is the start of
|
|||
// another block.
|
|||
break; |
|||
} |
|||
} |
|||
if (lastLineInFold) return { |
|||
from: CodeMirror.Pos(start.line, cm.getLine(start.line).length), |
|||
to: CodeMirror.Pos(lastLineInFold, cm.getLine(lastLineInFold).length) |
|||
}; |
|||
}); |
|||
|
|||
}); |
|||
@ -0,0 +1,49 @@ |
|||
// CodeMirror, copyright (c) by Marijn Haverbeke and others
|
|||
// Distributed under an MIT license: https://codemirror.net/LICENSE
|
|||
|
|||
(function(mod) { |
|||
if (typeof exports == "object" && typeof module == "object") // CommonJS
|
|||
mod(require("../../lib/codemirror")); |
|||
else if (typeof define == "function" && define.amd) // AMD
|
|||
define(["../../lib/codemirror"], mod); |
|||
else // Plain browser env
|
|||
mod(CodeMirror); |
|||
})(function(CodeMirror) { |
|||
"use strict"; |
|||
|
|||
CodeMirror.registerHelper("fold", "markdown", function(cm, start) { |
|||
var maxDepth = 100; |
|||
|
|||
function isHeader(lineNo) { |
|||
var tokentype = cm.getTokenTypeAt(CodeMirror.Pos(lineNo, 0)); |
|||
return tokentype && /\bheader\b/.test(tokentype); |
|||
} |
|||
|
|||
function headerLevel(lineNo, line, nextLine) { |
|||
var match = line && line.match(/^#+/); |
|||
if (match && isHeader(lineNo)) return match[0].length; |
|||
match = nextLine && nextLine.match(/^[=\-]+\s*$/); |
|||
if (match && isHeader(lineNo + 1)) return nextLine[0] == "=" ? 1 : 2; |
|||
return maxDepth; |
|||
} |
|||
|
|||
var firstLine = cm.getLine(start.line), nextLine = cm.getLine(start.line + 1); |
|||
var level = headerLevel(start.line, firstLine, nextLine); |
|||
if (level === maxDepth) return undefined; |
|||
|
|||
var lastLineNo = cm.lastLine(); |
|||
var end = start.line, nextNextLine = cm.getLine(end + 2); |
|||
while (end < lastLineNo) { |
|||
if (headerLevel(end + 1, nextLine, nextNextLine) <= level) break; |
|||
++end; |
|||
nextLine = nextNextLine; |
|||
nextNextLine = cm.getLine(end + 2); |
|||
} |
|||
|
|||
return { |
|||
from: CodeMirror.Pos(start.line, firstLine.length), |
|||
to: CodeMirror.Pos(end, cm.getLine(end).length) |
|||
}; |
|||
}); |
|||
|
|||
}); |
|||
@ -0,0 +1,184 @@ |
|||
// CodeMirror, copyright (c) by Marijn Haverbeke and others
|
|||
// Distributed under an MIT license: https://codemirror.net/LICENSE
|
|||
|
|||
(function(mod) { |
|||
if (typeof exports == "object" && typeof module == "object") // CommonJS
|
|||
mod(require("../../lib/codemirror")); |
|||
else if (typeof define == "function" && define.amd) // AMD
|
|||
define(["../../lib/codemirror"], mod); |
|||
else // Plain browser env
|
|||
mod(CodeMirror); |
|||
})(function(CodeMirror) { |
|||
"use strict"; |
|||
|
|||
var Pos = CodeMirror.Pos; |
|||
function cmp(a, b) { return a.line - b.line || a.ch - b.ch; } |
|||
|
|||
var nameStartChar = "A-Z_a-z\\u00C0-\\u00D6\\u00D8-\\u00F6\\u00F8-\\u02FF\\u0370-\\u037D\\u037F-\\u1FFF\\u200C-\\u200D\\u2070-\\u218F\\u2C00-\\u2FEF\\u3001-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFFD"; |
|||
var nameChar = nameStartChar + "\-\:\.0-9\\u00B7\\u0300-\\u036F\\u203F-\\u2040"; |
|||
var xmlTagStart = new RegExp("<(/?)([" + nameStartChar + "][" + nameChar + "]*)", "g"); |
|||
|
|||
function Iter(cm, line, ch, range) { |
|||
this.line = line; this.ch = ch; |
|||
this.cm = cm; this.text = cm.getLine(line); |
|||
this.min = range ? Math.max(range.from, cm.firstLine()) : cm.firstLine(); |
|||
this.max = range ? Math.min(range.to - 1, cm.lastLine()) : cm.lastLine(); |
|||
} |
|||
|
|||
function tagAt(iter, ch) { |
|||
var type = iter.cm.getTokenTypeAt(Pos(iter.line, ch)); |
|||
return type && /\btag\b/.test(type); |
|||
} |
|||
|
|||
function nextLine(iter) { |
|||
if (iter.line >= iter.max) return; |
|||
iter.ch = 0; |
|||
iter.text = iter.cm.getLine(++iter.line); |
|||
return true; |
|||
} |
|||
function prevLine(iter) { |
|||
if (iter.line <= iter.min) return; |
|||
iter.text = iter.cm.getLine(--iter.line); |
|||
iter.ch = iter.text.length; |
|||
return true; |
|||
} |
|||
|
|||
function toTagEnd(iter) { |
|||
for (;;) { |
|||
var gt = iter.text.indexOf(">", iter.ch); |
|||
if (gt == -1) { if (nextLine(iter)) continue; else return; } |
|||
if (!tagAt(iter, gt + 1)) { iter.ch = gt + 1; continue; } |
|||
var lastSlash = iter.text.lastIndexOf("/", gt); |
|||
var selfClose = lastSlash > -1 && !/\S/.test(iter.text.slice(lastSlash + 1, gt)); |
|||
iter.ch = gt + 1; |
|||
return selfClose ? "selfClose" : "regular"; |
|||
} |
|||
} |
|||
function toTagStart(iter) { |
|||
for (;;) { |
|||
var lt = iter.ch ? iter.text.lastIndexOf("<", iter.ch - 1) : -1; |
|||
if (lt == -1) { if (prevLine(iter)) continue; else return; } |
|||
if (!tagAt(iter, lt + 1)) { iter.ch = lt; continue; } |
|||
xmlTagStart.lastIndex = lt; |
|||
iter.ch = lt; |
|||
var match = xmlTagStart.exec(iter.text); |
|||
if (match && match.index == lt) return match; |
|||
} |
|||
} |
|||
|
|||
function toNextTag(iter) { |
|||
for (;;) { |
|||
xmlTagStart.lastIndex = iter.ch; |
|||
var found = xmlTagStart.exec(iter.text); |
|||
if (!found) { if (nextLine(iter)) continue; else return; } |
|||
if (!tagAt(iter, found.index + 1)) { iter.ch = found.index + 1; continue; } |
|||
iter.ch = found.index + found[0].length; |
|||
return found; |
|||
} |
|||
} |
|||
function toPrevTag(iter) { |
|||
for (;;) { |
|||
var gt = iter.ch ? iter.text.lastIndexOf(">", iter.ch - 1) : -1; |
|||
if (gt == -1) { if (prevLine(iter)) continue; else return; } |
|||
if (!tagAt(iter, gt + 1)) { iter.ch = gt; continue; } |
|||
var lastSlash = iter.text.lastIndexOf("/", gt); |
|||
var selfClose = lastSlash > -1 && !/\S/.test(iter.text.slice(lastSlash + 1, gt)); |
|||
iter.ch = gt + 1; |
|||
return selfClose ? "selfClose" : "regular"; |
|||
} |
|||
} |
|||
|
|||
function findMatchingClose(iter, tag) { |
|||
var stack = []; |
|||
for (;;) { |
|||
var next = toNextTag(iter), end, startLine = iter.line, startCh = iter.ch - (next ? next[0].length : 0); |
|||
if (!next || !(end = toTagEnd(iter))) return; |
|||
if (end == "selfClose") continue; |
|||
if (next[1]) { // closing tag
|
|||
for (var i = stack.length - 1; i >= 0; --i) if (stack[i] == next[2]) { |
|||
stack.length = i; |
|||
break; |
|||
} |
|||
if (i < 0 && (!tag || tag == next[2])) return { |
|||
tag: next[2], |
|||
from: Pos(startLine, startCh), |
|||
to: Pos(iter.line, iter.ch) |
|||
}; |
|||
} else { // opening tag
|
|||
stack.push(next[2]); |
|||
} |
|||
} |
|||
} |
|||
function findMatchingOpen(iter, tag) { |
|||
var stack = []; |
|||
for (;;) { |
|||
var prev = toPrevTag(iter); |
|||
if (!prev) return; |
|||
if (prev == "selfClose") { toTagStart(iter); continue; } |
|||
var endLine = iter.line, endCh = iter.ch; |
|||
var start = toTagStart(iter); |
|||
if (!start) return; |
|||
if (start[1]) { // closing tag
|
|||
stack.push(start[2]); |
|||
} else { // opening tag
|
|||
for (var i = stack.length - 1; i >= 0; --i) if (stack[i] == start[2]) { |
|||
stack.length = i; |
|||
break; |
|||
} |
|||
if (i < 0 && (!tag || tag == start[2])) return { |
|||
tag: start[2], |
|||
from: Pos(iter.line, iter.ch), |
|||
to: Pos(endLine, endCh) |
|||
}; |
|||
} |
|||
} |
|||
} |
|||
|
|||
CodeMirror.registerHelper("fold", "xml", function(cm, start) { |
|||
var iter = new Iter(cm, start.line, 0); |
|||
for (;;) { |
|||
var openTag = toNextTag(iter) |
|||
if (!openTag || iter.line != start.line) return |
|||
var end = toTagEnd(iter) |
|||
if (!end) return |
|||
if (!openTag[1] && end != "selfClose") { |
|||
var startPos = Pos(iter.line, iter.ch); |
|||
var endPos = findMatchingClose(iter, openTag[2]); |
|||
return endPos && cmp(endPos.from, startPos) > 0 ? {from: startPos, to: endPos.from} : null |
|||
} |
|||
} |
|||
}); |
|||
CodeMirror.findMatchingTag = function(cm, pos, range) { |
|||
var iter = new Iter(cm, pos.line, pos.ch, range); |
|||
if (iter.text.indexOf(">") == -1 && iter.text.indexOf("<") == -1) return; |
|||
var end = toTagEnd(iter), to = end && Pos(iter.line, iter.ch); |
|||
var start = end && toTagStart(iter); |
|||
if (!end || !start || cmp(iter, pos) > 0) return; |
|||
var here = {from: Pos(iter.line, iter.ch), to: to, tag: start[2]}; |
|||
if (end == "selfClose") return {open: here, close: null, at: "open"}; |
|||
|
|||
if (start[1]) { // closing tag
|
|||
return {open: findMatchingOpen(iter, start[2]), close: here, at: "close"}; |
|||
} else { // opening tag
|
|||
iter = new Iter(cm, to.line, to.ch, range); |
|||
return {open: here, close: findMatchingClose(iter, start[2]), at: "open"}; |
|||
} |
|||
}; |
|||
|
|||
CodeMirror.findEnclosingTag = function(cm, pos, range, tag) { |
|||
var iter = new Iter(cm, pos.line, pos.ch, range); |
|||
for (;;) { |
|||
var open = findMatchingOpen(iter, tag); |
|||
if (!open) break; |
|||
var forward = new Iter(cm, pos.line, pos.ch, range); |
|||
var close = findMatchingClose(forward, open.tag); |
|||
if (close) return {open: open, close: close}; |
|||
} |
|||
}; |
|||
|
|||
// Used by addon/edit/closetag.js
|
|||
CodeMirror.scanForClosingTag = function(cm, pos, name, end) { |
|||
var iter = new Iter(cm, pos.line, pos.ch, end ? {from: 0, to: end} : null); |
|||
return findMatchingClose(iter, name); |
|||
}; |
|||
}); |
|||
@ -0,0 +1,41 @@ |
|||
// CodeMirror, copyright (c) by Marijn Haverbeke and others
|
|||
// Distributed under an MIT license: https://codemirror.net/LICENSE
|
|||
|
|||
(function(mod) { |
|||
if (typeof exports == "object" && typeof module == "object") // CommonJS
|
|||
mod(require("../../lib/codemirror")); |
|||
else if (typeof define == "function" && define.amd) // AMD
|
|||
define(["../../lib/codemirror"], mod); |
|||
else // Plain browser env
|
|||
mod(CodeMirror); |
|||
})(function(CodeMirror) { |
|||
"use strict"; |
|||
|
|||
var WORD = /[\w$]+/, RANGE = 500; |
|||
|
|||
CodeMirror.registerHelper("hint", "anyword", function(editor, options) { |
|||
var word = options && options.word || WORD; |
|||
var range = options && options.range || RANGE; |
|||
var cur = editor.getCursor(), curLine = editor.getLine(cur.line); |
|||
var end = cur.ch, start = end; |
|||
while (start && word.test(curLine.charAt(start - 1))) --start; |
|||
var curWord = start != end && curLine.slice(start, end); |
|||
|
|||
var list = options && options.list || [], seen = {}; |
|||
var re = new RegExp(word.source, "g"); |
|||
for (var dir = -1; dir <= 1; dir += 2) { |
|||
var line = cur.line, endLine = Math.min(Math.max(line + dir * range, editor.firstLine()), editor.lastLine()) + dir; |
|||
for (; line != endLine; line += dir) { |
|||
var text = editor.getLine(line), m; |
|||
while (m = re.exec(text)) { |
|||
if (line == cur.line && m[0] === curWord) continue; |
|||
if ((!curWord || m[0].lastIndexOf(curWord, 0) == 0) && !Object.prototype.hasOwnProperty.call(seen, m[0])) { |
|||
seen[m[0]] = true; |
|||
list.push(m[0]); |
|||
} |
|||
} |
|||
} |
|||
} |
|||
return {list: list, from: CodeMirror.Pos(cur.line, start), to: CodeMirror.Pos(cur.line, end)}; |
|||
}); |
|||
}); |
|||
@ -0,0 +1,66 @@ |
|||
// CodeMirror, copyright (c) by Marijn Haverbeke and others
|
|||
// Distributed under an MIT license: https://codemirror.net/LICENSE
|
|||
|
|||
(function(mod) { |
|||
if (typeof exports == "object" && typeof module == "object") // CommonJS
|
|||
mod(require("../../lib/codemirror"), require("../../mode/css/css")); |
|||
else if (typeof define == "function" && define.amd) // AMD
|
|||
define(["../../lib/codemirror", "../../mode/css/css"], mod); |
|||
else // Plain browser env
|
|||
mod(CodeMirror); |
|||
})(function(CodeMirror) { |
|||
"use strict"; |
|||
|
|||
var pseudoClasses = {"active":1, "after":1, "before":1, "checked":1, "default":1, |
|||
"disabled":1, "empty":1, "enabled":1, "first-child":1, "first-letter":1, |
|||
"first-line":1, "first-of-type":1, "focus":1, "hover":1, "in-range":1, |
|||
"indeterminate":1, "invalid":1, "lang":1, "last-child":1, "last-of-type":1, |
|||
"link":1, "not":1, "nth-child":1, "nth-last-child":1, "nth-last-of-type":1, |
|||
"nth-of-type":1, "only-of-type":1, "only-child":1, "optional":1, "out-of-range":1, |
|||
"placeholder":1, "read-only":1, "read-write":1, "required":1, "root":1, |
|||
"selection":1, "target":1, "valid":1, "visited":1 |
|||
}; |
|||
|
|||
CodeMirror.registerHelper("hint", "css", function(cm) { |
|||
var cur = cm.getCursor(), token = cm.getTokenAt(cur); |
|||
var inner = CodeMirror.innerMode(cm.getMode(), token.state); |
|||
if (inner.mode.name != "css") return; |
|||
|
|||
if (token.type == "keyword" && "!important".indexOf(token.string) == 0) |
|||
return {list: ["!important"], from: CodeMirror.Pos(cur.line, token.start), |
|||
to: CodeMirror.Pos(cur.line, token.end)}; |
|||
|
|||
var start = token.start, end = cur.ch, word = token.string.slice(0, end - start); |
|||
if (/[^\w$_-]/.test(word)) { |
|||
word = ""; start = end = cur.ch; |
|||
} |
|||
|
|||
var spec = CodeMirror.resolveMode("text/css"); |
|||
|
|||
var result = []; |
|||
function add(keywords) { |
|||
for (var name in keywords) |
|||
if (!word || name.lastIndexOf(word, 0) == 0) |
|||
result.push(name); |
|||
} |
|||
|
|||
var st = inner.state.state; |
|||
if (st == "pseudo" || token.type == "variable-3") { |
|||
add(pseudoClasses); |
|||
} else if (st == "block" || st == "maybeprop") { |
|||
add(spec.propertyKeywords); |
|||
} else if (st == "prop" || st == "parens" || st == "at" || st == "params") { |
|||
add(spec.valueKeywords); |
|||
add(spec.colorKeywords); |
|||
} else if (st == "media" || st == "media_parens") { |
|||
add(spec.mediaTypes); |
|||
add(spec.mediaFeatures); |
|||
} |
|||
|
|||
if (result.length) return { |
|||
list: result, |
|||
from: CodeMirror.Pos(cur.line, start), |
|||
to: CodeMirror.Pos(cur.line, end) |
|||
}; |
|||
}); |
|||
}); |
|||
@ -0,0 +1,351 @@ |
|||
// CodeMirror, copyright (c) by Marijn Haverbeke and others
|
|||
// Distributed under an MIT license: https://codemirror.net/LICENSE
|
|||
|
|||
(function(mod) { |
|||
if (typeof exports == "object" && typeof module == "object") // CommonJS
|
|||
mod(require("../../lib/codemirror"), require("./xml-hint")); |
|||
else if (typeof define == "function" && define.amd) // AMD
|
|||
define(["../../lib/codemirror", "./xml-hint"], mod); |
|||
else // Plain browser env
|
|||
mod(CodeMirror); |
|||
})(function(CodeMirror) { |
|||
"use strict"; |
|||
|
|||
var langs = "ab aa af ak sq am ar an hy as av ae ay az bm ba eu be bn bh bi bs br bg my ca ch ce ny zh cv kw co cr hr cs da dv nl dz en eo et ee fo fj fi fr ff gl ka de el gn gu ht ha he hz hi ho hu ia id ie ga ig ik io is it iu ja jv kl kn kr ks kk km ki rw ky kv kg ko ku kj la lb lg li ln lo lt lu lv gv mk mg ms ml mt mi mr mh mn na nv nb nd ne ng nn no ii nr oc oj cu om or os pa pi fa pl ps pt qu rm rn ro ru sa sc sd se sm sg sr gd sn si sk sl so st es su sw ss sv ta te tg th ti bo tk tl tn to tr ts tt tw ty ug uk ur uz ve vi vo wa cy wo fy xh yi yo za zu".split(" "); |
|||
var targets = ["_blank", "_self", "_top", "_parent"]; |
|||
var charsets = ["ascii", "utf-8", "utf-16", "latin1", "latin1"]; |
|||
var methods = ["get", "post", "put", "delete"]; |
|||
var encs = ["application/x-www-form-urlencoded", "multipart/form-data", "text/plain"]; |
|||
var media = ["all", "screen", "print", "embossed", "braille", "handheld", "print", "projection", "screen", "tty", "tv", "speech", |
|||
"3d-glasses", "resolution [>][<][=] [X]", "device-aspect-ratio: X/Y", "orientation:portrait", |
|||
"orientation:landscape", "device-height: [X]", "device-width: [X]"]; |
|||
var s = { attrs: {} }; // Simple tag, reused for a whole lot of tags
|
|||
|
|||
var data = { |
|||
a: { |
|||
attrs: { |
|||
href: null, ping: null, type: null, |
|||
media: media, |
|||
target: targets, |
|||
hreflang: langs |
|||
} |
|||
}, |
|||
abbr: s, |
|||
acronym: s, |
|||
address: s, |
|||
applet: s, |
|||
area: { |
|||
attrs: { |
|||
alt: null, coords: null, href: null, target: null, ping: null, |
|||
media: media, hreflang: langs, type: null, |
|||
shape: ["default", "rect", "circle", "poly"] |
|||
} |
|||
}, |
|||
article: s, |
|||
aside: s, |
|||
audio: { |
|||
attrs: { |
|||
src: null, mediagroup: null, |
|||
crossorigin: ["anonymous", "use-credentials"], |
|||
preload: ["none", "metadata", "auto"], |
|||
autoplay: ["", "autoplay"], |
|||
loop: ["", "loop"], |
|||
controls: ["", "controls"] |
|||
} |
|||
}, |
|||
b: s, |
|||
base: { attrs: { href: null, target: targets } }, |
|||
basefont: s, |
|||
bdi: s, |
|||
bdo: s, |
|||
big: s, |
|||
blockquote: { attrs: { cite: null } }, |
|||
body: s, |
|||
br: s, |
|||
button: { |
|||
attrs: { |
|||
form: null, formaction: null, name: null, value: null, |
|||
autofocus: ["", "autofocus"], |
|||
disabled: ["", "autofocus"], |
|||
formenctype: encs, |
|||
formmethod: methods, |
|||
formnovalidate: ["", "novalidate"], |
|||
formtarget: targets, |
|||
type: ["submit", "reset", "button"] |
|||
} |
|||
}, |
|||
canvas: { attrs: { width: null, height: null } }, |
|||
caption: s, |
|||
center: s, |
|||
cite: s, |
|||
code: s, |
|||
col: { attrs: { span: null } }, |
|||
colgroup: { attrs: { span: null } }, |
|||
command: { |
|||
attrs: { |
|||
type: ["command", "checkbox", "radio"], |
|||
label: null, icon: null, radiogroup: null, command: null, title: null, |
|||
disabled: ["", "disabled"], |
|||
checked: ["", "checked"] |
|||
} |
|||
}, |
|||
data: { attrs: { value: null } }, |
|||
datagrid: { attrs: { disabled: ["", "disabled"], multiple: ["", "multiple"] } }, |
|||
datalist: { attrs: { data: null } }, |
|||
dd: s, |
|||
del: { attrs: { cite: null, datetime: null } }, |
|||
details: { attrs: { open: ["", "open"] } }, |
|||
dfn: s, |
|||
dir: s, |
|||
div: s, |
|||
dialog: { attrs: { open: null } }, |
|||
dl: s, |
|||
dt: s, |
|||
em: s, |
|||
embed: { attrs: { src: null, type: null, width: null, height: null } }, |
|||
eventsource: { attrs: { src: null } }, |
|||
fieldset: { attrs: { disabled: ["", "disabled"], form: null, name: null } }, |
|||
figcaption: s, |
|||
figure: s, |
|||
font: s, |
|||
footer: s, |
|||
form: { |
|||
attrs: { |
|||
action: null, name: null, |
|||
"accept-charset": charsets, |
|||
autocomplete: ["on", "off"], |
|||
enctype: encs, |
|||
method: methods, |
|||
novalidate: ["", "novalidate"], |
|||
target: targets |
|||
} |
|||
}, |
|||
frame: s, |
|||
frameset: s, |
|||
h1: s, h2: s, h3: s, h4: s, h5: s, h6: s, |
|||
head: { |
|||
attrs: {}, |
|||
children: ["title", "base", "link", "style", "meta", "script", "noscript", "command"] |
|||
}, |
|||
header: s, |
|||
hgroup: s, |
|||
hr: s, |
|||
html: { |
|||
attrs: { manifest: null }, |
|||
children: ["head", "body"] |
|||
}, |
|||
i: s, |
|||
iframe: { |
|||
attrs: { |
|||
src: null, srcdoc: null, name: null, width: null, height: null, |
|||
sandbox: ["allow-top-navigation", "allow-same-origin", "allow-forms", "allow-scripts"], |
|||
seamless: ["", "seamless"] |
|||
} |
|||
}, |
|||
img: { |
|||
attrs: { |
|||
alt: null, src: null, ismap: null, usemap: null, width: null, height: null, |
|||
crossorigin: ["anonymous", "use-credentials"] |
|||
} |
|||
}, |
|||
input: { |
|||
attrs: { |
|||
alt: null, dirname: null, form: null, formaction: null, |
|||
height: null, list: null, max: null, maxlength: null, min: null, |
|||
name: null, pattern: null, placeholder: null, size: null, src: null, |
|||
step: null, value: null, width: null, |
|||
accept: ["audio/*", "video/*", "image/*"], |
|||
autocomplete: ["on", "off"], |
|||
autofocus: ["", "autofocus"], |
|||
checked: ["", "checked"], |
|||
disabled: ["", "disabled"], |
|||
formenctype: encs, |
|||
formmethod: methods, |
|||
formnovalidate: ["", "novalidate"], |
|||
formtarget: targets, |
|||
multiple: ["", "multiple"], |
|||
readonly: ["", "readonly"], |
|||
required: ["", "required"], |
|||
type: ["hidden", "text", "search", "tel", "url", "email", "password", "datetime", "date", "month", |
|||
"week", "time", "datetime-local", "number", "range", "color", "checkbox", "radio", |
|||
"file", "submit", "image", "reset", "button"] |
|||
} |
|||
}, |
|||
ins: { attrs: { cite: null, datetime: null } }, |
|||
kbd: s, |
|||
keygen: { |
|||
attrs: { |
|||
challenge: null, form: null, name: null, |
|||
autofocus: ["", "autofocus"], |
|||
disabled: ["", "disabled"], |
|||
keytype: ["RSA"] |
|||
} |
|||
}, |
|||
label: { attrs: { "for": null, form: null } }, |
|||
legend: s, |
|||
li: { attrs: { value: null } }, |
|||
link: { |
|||
attrs: { |
|||
href: null, type: null, |
|||
hreflang: langs, |
|||
media: media, |
|||
sizes: ["all", "16x16", "16x16 32x32", "16x16 32x32 64x64"] |
|||
} |
|||
}, |
|||
map: { attrs: { name: null } }, |
|||
mark: s, |
|||
menu: { attrs: { label: null, type: ["list", "context", "toolbar"] } }, |
|||
meta: { |
|||
attrs: { |
|||
content: null, |
|||
charset: charsets, |
|||
name: ["viewport", "application-name", "author", "description", "generator", "keywords"], |
|||
"http-equiv": ["content-language", "content-type", "default-style", "refresh"] |
|||
} |
|||
}, |
|||
meter: { attrs: { value: null, min: null, low: null, high: null, max: null, optimum: null } }, |
|||
nav: s, |
|||
noframes: s, |
|||
noscript: s, |
|||
object: { |
|||
attrs: { |
|||
data: null, type: null, name: null, usemap: null, form: null, width: null, height: null, |
|||
typemustmatch: ["", "typemustmatch"] |
|||
} |
|||
}, |
|||
ol: { attrs: { reversed: ["", "reversed"], start: null, type: ["1", "a", "A", "i", "I"] } }, |
|||
optgroup: { attrs: { disabled: ["", "disabled"], label: null } }, |
|||
option: { attrs: { disabled: ["", "disabled"], label: null, selected: ["", "selected"], value: null } }, |
|||
output: { attrs: { "for": null, form: null, name: null } }, |
|||
p: s, |
|||
param: { attrs: { name: null, value: null } }, |
|||
pre: s, |
|||
progress: { attrs: { value: null, max: null } }, |
|||
q: { attrs: { cite: null } }, |
|||
rp: s, |
|||
rt: s, |
|||
ruby: s, |
|||
s: s, |
|||
samp: s, |
|||
script: { |
|||
attrs: { |
|||
type: ["text/javascript"], |
|||
src: null, |
|||
async: ["", "async"], |
|||
defer: ["", "defer"], |
|||
charset: charsets |
|||
} |
|||
}, |
|||
section: s, |
|||
select: { |
|||
attrs: { |
|||
form: null, name: null, size: null, |
|||
autofocus: ["", "autofocus"], |
|||
disabled: ["", "disabled"], |
|||
multiple: ["", "multiple"] |
|||
} |
|||
}, |
|||
small: s, |
|||
source: { attrs: { src: null, type: null, media: null } }, |
|||
span: s, |
|||
strike: s, |
|||
strong: s, |
|||
style: { |
|||
attrs: { |
|||
type: ["text/css"], |
|||
media: media, |
|||
scoped: null |
|||
} |
|||
}, |
|||
sub: s, |
|||
summary: s, |
|||
sup: s, |
|||
table: s, |
|||
tbody: s, |
|||
td: { attrs: { colspan: null, rowspan: null, headers: null } }, |
|||
textarea: { |
|||
attrs: { |
|||
dirname: null, form: null, maxlength: null, name: null, placeholder: null, |
|||
rows: null, cols: null, |
|||
autofocus: ["", "autofocus"], |
|||
disabled: ["", "disabled"], |
|||
readonly: ["", "readonly"], |
|||
required: ["", "required"], |
|||
wrap: ["soft", "hard"] |
|||
} |
|||
}, |
|||
tfoot: s, |
|||
th: { attrs: { colspan: null, rowspan: null, headers: null, scope: ["row", "col", "rowgroup", "colgroup"] } }, |
|||
thead: s, |
|||
time: { attrs: { datetime: null } }, |
|||
title: s, |
|||
tr: s, |
|||
track: { |
|||
attrs: { |
|||
src: null, label: null, "default": null, |
|||
kind: ["subtitles", "captions", "descriptions", "chapters", "metadata"], |
|||
srclang: langs |
|||
} |
|||
}, |
|||
tt: s, |
|||
u: s, |
|||
ul: s, |
|||
"var": s, |
|||
video: { |
|||
attrs: { |
|||
src: null, poster: null, width: null, height: null, |
|||
crossorigin: ["anonymous", "use-credentials"], |
|||
preload: ["auto", "metadata", "none"], |
|||
autoplay: ["", "autoplay"], |
|||
mediagroup: ["movie"], |
|||
muted: ["", "muted"], |
|||
controls: ["", "controls"] |
|||
} |
|||
}, |
|||
wbr: s |
|||
}; |
|||
|
|||
var globalAttrs = { |
|||
accesskey: ["a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z", "0", "1", "2", "3", "4", "5", "6", "7", "8", "9"], |
|||
"class": null, |
|||
contenteditable: ["true", "false"], |
|||
contextmenu: null, |
|||
dir: ["ltr", "rtl", "auto"], |
|||
draggable: ["true", "false", "auto"], |
|||
dropzone: ["copy", "move", "link", "string:", "file:"], |
|||
hidden: ["hidden"], |
|||
id: null, |
|||
inert: ["inert"], |
|||
itemid: null, |
|||
itemprop: null, |
|||
itemref: null, |
|||
itemscope: ["itemscope"], |
|||
itemtype: null, |
|||
lang: ["en", "es"], |
|||
spellcheck: ["true", "false"], |
|||
autocorrect: ["true", "false"], |
|||
autocapitalize: ["true", "false"], |
|||
style: null, |
|||
tabindex: ["1", "2", "3", "4", "5", "6", "7", "8", "9"], |
|||
title: null, |
|||
translate: ["yes", "no"], |
|||
onclick: null, |
|||
rel: ["stylesheet", "alternate", "author", "bookmark", "help", "license", "next", "nofollow", "noreferrer", "prefetch", "prev", "search", "tag"] |
|||
}; |
|||
function populate(obj) { |
|||
for (var attr in globalAttrs) if (globalAttrs.hasOwnProperty(attr)) |
|||
obj.attrs[attr] = globalAttrs[attr]; |
|||
} |
|||
|
|||
populate(s); |
|||
for (var tag in data) if (data.hasOwnProperty(tag) && data[tag] != s) |
|||
populate(data[tag]); |
|||
|
|||
CodeMirror.htmlSchema = data; |
|||
function htmlHint(cm, options) { |
|||
var local = {schemaInfo: data}; |
|||
if (options) for (var opt in options) local[opt] = options[opt]; |
|||
return CodeMirror.hint.xml(cm, local); |
|||
} |
|||
CodeMirror.registerHelper("hint", "html", htmlHint); |
|||
}); |
|||
@ -0,0 +1,162 @@ |
|||
// CodeMirror, copyright (c) by Marijn Haverbeke and others
|
|||
// Distributed under an MIT license: https://codemirror.net/LICENSE
|
|||
|
|||
(function(mod) { |
|||
if (typeof exports == "object" && typeof module == "object") // CommonJS
|
|||
mod(require("../../lib/codemirror")); |
|||
else if (typeof define == "function" && define.amd) // AMD
|
|||
define(["../../lib/codemirror"], mod); |
|||
else // Plain browser env
|
|||
mod(CodeMirror); |
|||
})(function(CodeMirror) { |
|||
var Pos = CodeMirror.Pos; |
|||
|
|||
function forEach(arr, f) { |
|||
for (var i = 0, e = arr.length; i < e; ++i) f(arr[i]); |
|||
} |
|||
|
|||
function arrayContains(arr, item) { |
|||
if (!Array.prototype.indexOf) { |
|||
var i = arr.length; |
|||
while (i--) { |
|||
if (arr[i] === item) { |
|||
return true; |
|||
} |
|||
} |
|||
return false; |
|||
} |
|||
return arr.indexOf(item) != -1; |
|||
} |
|||
|
|||
function scriptHint(editor, keywords, getToken, options) { |
|||
// Find the token at the cursor
|
|||
var cur = editor.getCursor(), token = getToken(editor, cur); |
|||
if (/\b(?:string|comment)\b/.test(token.type)) return; |
|||
var innerMode = CodeMirror.innerMode(editor.getMode(), token.state); |
|||
if (innerMode.mode.helperType === "json") return; |
|||
token.state = innerMode.state; |
|||
|
|||
// If it's not a 'word-style' token, ignore the token.
|
|||
if (!/^[\w$_]*$/.test(token.string)) { |
|||
token = {start: cur.ch, end: cur.ch, string: "", state: token.state, |
|||
type: token.string == "." ? "property" : null}; |
|||
} else if (token.end > cur.ch) { |
|||
token.end = cur.ch; |
|||
token.string = token.string.slice(0, cur.ch - token.start); |
|||
} |
|||
|
|||
var tprop = token; |
|||
// If it is a property, find out what it is a property of.
|
|||
while (tprop.type == "property") { |
|||
tprop = getToken(editor, Pos(cur.line, tprop.start)); |
|||
if (tprop.string != ".") return; |
|||
tprop = getToken(editor, Pos(cur.line, tprop.start)); |
|||
if (!context) var context = []; |
|||
context.push(tprop); |
|||
} |
|||
return {list: getCompletions(token, context, keywords, options), |
|||
from: Pos(cur.line, token.start), |
|||
to: Pos(cur.line, token.end)}; |
|||
} |
|||
|
|||
function javascriptHint(editor, options) { |
|||
return scriptHint(editor, javascriptKeywords, |
|||
function (e, cur) {return e.getTokenAt(cur);}, |
|||
options); |
|||
}; |
|||
CodeMirror.registerHelper("hint", "javascript", javascriptHint); |
|||
|
|||
function getCoffeeScriptToken(editor, cur) { |
|||
// This getToken, it is for coffeescript, imitates the behavior of
|
|||
// getTokenAt method in javascript.js, that is, returning "property"
|
|||
// type and treat "." as independent token.
|
|||
var token = editor.getTokenAt(cur); |
|||
if (cur.ch == token.start + 1 && token.string.charAt(0) == '.') { |
|||
token.end = token.start; |
|||
token.string = '.'; |
|||
token.type = "property"; |
|||
} |
|||
else if (/^\.[\w$_]*$/.test(token.string)) { |
|||
token.type = "property"; |
|||
token.start++; |
|||
token.string = token.string.replace(/\./, ''); |
|||
} |
|||
return token; |
|||
} |
|||
|
|||
function coffeescriptHint(editor, options) { |
|||
return scriptHint(editor, coffeescriptKeywords, getCoffeeScriptToken, options); |
|||
} |
|||
CodeMirror.registerHelper("hint", "coffeescript", coffeescriptHint); |
|||
|
|||
var stringProps = ("charAt charCodeAt indexOf lastIndexOf substring substr slice trim trimLeft trimRight " + |
|||
"toUpperCase toLowerCase split concat match replace search").split(" "); |
|||
var arrayProps = ("length concat join splice push pop shift unshift slice reverse sort indexOf " + |
|||
"lastIndexOf every some filter forEach map reduce reduceRight ").split(" "); |
|||
var funcProps = "prototype apply call bind".split(" "); |
|||
var javascriptKeywords = ("break case catch class const continue debugger default delete do else export extends false finally for function " + |
|||
"if in import instanceof new null return super switch this throw true try typeof var void while with yield").split(" "); |
|||
var coffeescriptKeywords = ("and break catch class continue delete do else extends false finally for " + |
|||
"if in instanceof isnt new no not null of off on or return switch then throw true try typeof until void while with yes").split(" "); |
|||
|
|||
function forAllProps(obj, callback) { |
|||
if (!Object.getOwnPropertyNames || !Object.getPrototypeOf) { |
|||
for (var name in obj) callback(name) |
|||
} else { |
|||
for (var o = obj; o; o = Object.getPrototypeOf(o)) |
|||
Object.getOwnPropertyNames(o).forEach(callback) |
|||
} |
|||
} |
|||
|
|||
function getCompletions(token, context, keywords, options) { |
|||
var found = [], start = token.string, global = options && options.globalScope || window; |
|||
function maybeAdd(str) { |
|||
if (str.lastIndexOf(start, 0) == 0 && !arrayContains(found, str)) found.push(str); |
|||
} |
|||
function gatherCompletions(obj) { |
|||
if (typeof obj == "string") forEach(stringProps, maybeAdd); |
|||
else if (obj instanceof Array) forEach(arrayProps, maybeAdd); |
|||
else if (obj instanceof Function) forEach(funcProps, maybeAdd); |
|||
forAllProps(obj, maybeAdd) |
|||
} |
|||
|
|||
if (context && context.length) { |
|||
// If this is a property, see if it belongs to some object we can
|
|||
// find in the current environment.
|
|||
var obj = context.pop(), base; |
|||
if (obj.type && obj.type.indexOf("variable") === 0) { |
|||
if (options && options.additionalContext) |
|||
base = options.additionalContext[obj.string]; |
|||
if (!options || options.useGlobalScope !== false) |
|||
base = base || global[obj.string]; |
|||
} else if (obj.type == "string") { |
|||
base = ""; |
|||
} else if (obj.type == "atom") { |
|||
base = 1; |
|||
} else if (obj.type == "function") { |
|||
if (global.jQuery != null && (obj.string == '$' || obj.string == 'jQuery') && |
|||
(typeof global.jQuery == 'function')) |
|||
base = global.jQuery(); |
|||
else if (global._ != null && (obj.string == '_') && (typeof global._ == 'function')) |
|||
base = global._(); |
|||
} |
|||
while (base != null && context.length) |
|||
base = base[context.pop().string]; |
|||
if (base != null) gatherCompletions(base); |
|||
} else { |
|||
// If not, just look in the global object, any local scope, and optional additional-context
|
|||
// (reading into JS mode internals to get at the local and global variables)
|
|||
for (var v = token.state.localVars; v; v = v.next) maybeAdd(v.name); |
|||
for (var c = token.state.context; c; c = c.prev) |
|||
for (var v = c.vars; v; v = v.next) maybeAdd(v.name) |
|||
for (var v = token.state.globalVars; v; v = v.next) maybeAdd(v.name); |
|||
if (options && options.additionalContext != null) |
|||
for (var key in options.additionalContext) |
|||
maybeAdd(key); |
|||
if (!options || options.useGlobalScope !== false) |
|||
gatherCompletions(global); |
|||
forEach(keywords, maybeAdd); |
|||
} |
|||
return found; |
|||
} |
|||
}); |
|||
@ -0,0 +1,36 @@ |
|||
.CodeMirror-hints { |
|||
position: absolute; |
|||
z-index: 10; |
|||
overflow: hidden; |
|||
list-style: none; |
|||
|
|||
margin: 0; |
|||
padding: 2px; |
|||
|
|||
-webkit-box-shadow: 2px 3px 5px rgba(0,0,0,.2); |
|||
-moz-box-shadow: 2px 3px 5px rgba(0,0,0,.2); |
|||
box-shadow: 2px 3px 5px rgba(0,0,0,.2); |
|||
border-radius: 3px; |
|||
border: 1px solid silver; |
|||
|
|||
background: white; |
|||
font-size: 90%; |
|||
font-family: monospace; |
|||
|
|||
max-height: 20em; |
|||
overflow-y: auto; |
|||
} |
|||
|
|||
.CodeMirror-hint { |
|||
margin: 0; |
|||
padding: 0 4px; |
|||
border-radius: 2px; |
|||
white-space: pre; |
|||
color: black; |
|||
cursor: pointer; |
|||
} |
|||
|
|||
li.CodeMirror-hint-active { |
|||
background: #08f; |
|||
color: white; |
|||
} |
|||
@ -0,0 +1,529 @@ |
|||
// CodeMirror, copyright (c) by Marijn Haverbeke and others
|
|||
// Distributed under an MIT license: https://codemirror.net/LICENSE
|
|||
|
|||
// declare global: DOMRect
|
|||
|
|||
(function(mod) { |
|||
if (typeof exports == "object" && typeof module == "object") // CommonJS
|
|||
mod(require("../../lib/codemirror")); |
|||
else if (typeof define == "function" && define.amd) // AMD
|
|||
define(["../../lib/codemirror"], mod); |
|||
else // Plain browser env
|
|||
mod(CodeMirror); |
|||
})(function(CodeMirror) { |
|||
"use strict"; |
|||
|
|||
var HINT_ELEMENT_CLASS = "CodeMirror-hint"; |
|||
var ACTIVE_HINT_ELEMENT_CLASS = "CodeMirror-hint-active"; |
|||
|
|||
// This is the old interface, kept around for now to stay
|
|||
// backwards-compatible.
|
|||
CodeMirror.showHint = function(cm, getHints, options) { |
|||
if (!getHints) return cm.showHint(options); |
|||
if (options && options.async) getHints.async = true; |
|||
var newOpts = {hint: getHints}; |
|||
if (options) for (var prop in options) newOpts[prop] = options[prop]; |
|||
return cm.showHint(newOpts); |
|||
}; |
|||
|
|||
CodeMirror.defineExtension("showHint", function(options) { |
|||
options = parseOptions(this, this.getCursor("start"), options); |
|||
var selections = this.listSelections() |
|||
if (selections.length > 1) return; |
|||
// By default, don't allow completion when something is selected.
|
|||
// A hint function can have a `supportsSelection` property to
|
|||
// indicate that it can handle selections.
|
|||
if (this.somethingSelected()) { |
|||
if (!options.hint.supportsSelection) return; |
|||
// Don't try with cross-line selections
|
|||
for (var i = 0; i < selections.length; i++) |
|||
if (selections[i].head.line != selections[i].anchor.line) return; |
|||
} |
|||
|
|||
if (this.state.completionActive) this.state.completionActive.close(); |
|||
var completion = this.state.completionActive = new Completion(this, options); |
|||
if (!completion.options.hint) return; |
|||
|
|||
CodeMirror.signal(this, "startCompletion", this); |
|||
completion.update(true); |
|||
}); |
|||
|
|||
CodeMirror.defineExtension("closeHint", function() { |
|||
if (this.state.completionActive) this.state.completionActive.close() |
|||
}) |
|||
|
|||
function Completion(cm, options) { |
|||
this.cm = cm; |
|||
this.options = options; |
|||
this.widget = null; |
|||
this.debounce = 0; |
|||
this.tick = 0; |
|||
this.startPos = this.cm.getCursor("start"); |
|||
this.startLen = this.cm.getLine(this.startPos.line).length - this.cm.getSelection().length; |
|||
|
|||
if (this.options.updateOnCursorActivity) { |
|||
var self = this; |
|||
cm.on("cursorActivity", this.activityFunc = function() { self.cursorActivity(); }); |
|||
} |
|||
} |
|||
|
|||
var requestAnimationFrame = window.requestAnimationFrame || function(fn) { |
|||
return setTimeout(fn, 1000/60); |
|||
}; |
|||
var cancelAnimationFrame = window.cancelAnimationFrame || clearTimeout; |
|||
|
|||
Completion.prototype = { |
|||
close: function() { |
|||
if (!this.active()) return; |
|||
this.cm.state.completionActive = null; |
|||
this.tick = null; |
|||
if (this.options.updateOnCursorActivity) { |
|||
this.cm.off("cursorActivity", this.activityFunc); |
|||
} |
|||
|
|||
if (this.widget && this.data) CodeMirror.signal(this.data, "close"); |
|||
if (this.widget) this.widget.close(); |
|||
CodeMirror.signal(this.cm, "endCompletion", this.cm); |
|||
}, |
|||
|
|||
active: function() { |
|||
return this.cm.state.completionActive == this; |
|||
}, |
|||
|
|||
pick: function(data, i) { |
|||
var completion = data.list[i], self = this; |
|||
this.cm.operation(function() { |
|||
if (completion.hint) |
|||
completion.hint(self.cm, data, completion); |
|||
else |
|||
self.cm.replaceRange(getText(completion), completion.from || data.from, |
|||
completion.to || data.to, "complete"); |
|||
CodeMirror.signal(data, "pick", completion); |
|||
self.cm.scrollIntoView(); |
|||
}); |
|||
if (this.options.closeOnPick) { |
|||
this.close(); |
|||
} |
|||
}, |
|||
|
|||
cursorActivity: function() { |
|||
if (this.debounce) { |
|||
cancelAnimationFrame(this.debounce); |
|||
this.debounce = 0; |
|||
} |
|||
|
|||
var identStart = this.startPos; |
|||
if(this.data) { |
|||
identStart = this.data.from; |
|||
} |
|||
|
|||
var pos = this.cm.getCursor(), line = this.cm.getLine(pos.line); |
|||
if (pos.line != this.startPos.line || line.length - pos.ch != this.startLen - this.startPos.ch || |
|||
pos.ch < identStart.ch || this.cm.somethingSelected() || |
|||
(!pos.ch || this.options.closeCharacters.test(line.charAt(pos.ch - 1)))) { |
|||
this.close(); |
|||
} else { |
|||
var self = this; |
|||
this.debounce = requestAnimationFrame(function() {self.update();}); |
|||
if (this.widget) this.widget.disable(); |
|||
} |
|||
}, |
|||
|
|||
update: function(first) { |
|||
if (this.tick == null) return |
|||
var self = this, myTick = ++this.tick |
|||
fetchHints(this.options.hint, this.cm, this.options, function(data) { |
|||
if (self.tick == myTick) self.finishUpdate(data, first) |
|||
}) |
|||
}, |
|||
|
|||
finishUpdate: function(data, first) { |
|||
if (this.data) CodeMirror.signal(this.data, "update"); |
|||
|
|||
var picked = (this.widget && this.widget.picked) || (first && this.options.completeSingle); |
|||
if (this.widget) this.widget.close(); |
|||
|
|||
this.data = data; |
|||
|
|||
if (data && data.list.length) { |
|||
if (picked && data.list.length == 1) { |
|||
this.pick(data, 0); |
|||
} else { |
|||
this.widget = new Widget(this, data); |
|||
CodeMirror.signal(data, "shown"); |
|||
} |
|||
} |
|||
} |
|||
}; |
|||
|
|||
function parseOptions(cm, pos, options) { |
|||
var editor = cm.options.hintOptions; |
|||
var out = {}; |
|||
for (var prop in defaultOptions) out[prop] = defaultOptions[prop]; |
|||
if (editor) for (var prop in editor) |
|||
if (editor[prop] !== undefined) out[prop] = editor[prop]; |
|||
if (options) for (var prop in options) |
|||
if (options[prop] !== undefined) out[prop] = options[prop]; |
|||
if (out.hint.resolve) out.hint = out.hint.resolve(cm, pos) |
|||
return out; |
|||
} |
|||
|
|||
function getText(completion) { |
|||
if (typeof completion == "string") return completion; |
|||
else return completion.text; |
|||
} |
|||
|
|||
function buildKeyMap(completion, handle) { |
|||
var baseMap = { |
|||
Up: function() {handle.moveFocus(-1);}, |
|||
Down: function() {handle.moveFocus(1);}, |
|||
PageUp: function() {handle.moveFocus(-handle.menuSize() + 1, true);}, |
|||
PageDown: function() {handle.moveFocus(handle.menuSize() - 1, true);}, |
|||
Home: function() {handle.setFocus(0);}, |
|||
End: function() {handle.setFocus(handle.length - 1);}, |
|||
Enter: handle.pick, |
|||
Tab: handle.pick, |
|||
Esc: handle.close |
|||
}; |
|||
|
|||
var mac = /Mac/.test(navigator.platform); |
|||
|
|||
if (mac) { |
|||
baseMap["Ctrl-P"] = function() {handle.moveFocus(-1);}; |
|||
baseMap["Ctrl-N"] = function() {handle.moveFocus(1);}; |
|||
} |
|||
|
|||
var custom = completion.options.customKeys; |
|||
var ourMap = custom ? {} : baseMap; |
|||
function addBinding(key, val) { |
|||
var bound; |
|||
if (typeof val != "string") |
|||
bound = function(cm) { return val(cm, handle); }; |
|||
// This mechanism is deprecated
|
|||
else if (baseMap.hasOwnProperty(val)) |
|||
bound = baseMap[val]; |
|||
else |
|||
bound = val; |
|||
ourMap[key] = bound; |
|||
} |
|||
if (custom) |
|||
for (var key in custom) if (custom.hasOwnProperty(key)) |
|||
addBinding(key, custom[key]); |
|||
var extra = completion.options.extraKeys; |
|||
if (extra) |
|||
for (var key in extra) if (extra.hasOwnProperty(key)) |
|||
addBinding(key, extra[key]); |
|||
return ourMap; |
|||
} |
|||
|
|||
function getHintElement(hintsElement, el) { |
|||
while (el && el != hintsElement) { |
|||
if (el.nodeName.toUpperCase() === "LI" && el.parentNode == hintsElement) return el; |
|||
el = el.parentNode; |
|||
} |
|||
} |
|||
|
|||
function Widget(completion, data) { |
|||
this.id = "cm-complete-" + Math.floor(Math.random(1e6)) |
|||
this.completion = completion; |
|||
this.data = data; |
|||
this.picked = false; |
|||
var widget = this, cm = completion.cm; |
|||
var ownerDocument = cm.getInputField().ownerDocument; |
|||
var parentWindow = ownerDocument.defaultView || ownerDocument.parentWindow; |
|||
|
|||
var hints = this.hints = ownerDocument.createElement("ul"); |
|||
hints.setAttribute("role", "listbox") |
|||
hints.setAttribute("aria-expanded", "true") |
|||
hints.id = this.id |
|||
var theme = completion.cm.options.theme; |
|||
hints.className = "CodeMirror-hints " + theme; |
|||
this.selectedHint = data.selectedHint || 0; |
|||
|
|||
var completions = data.list; |
|||
for (var i = 0; i < completions.length; ++i) { |
|||
var elt = hints.appendChild(ownerDocument.createElement("li")), cur = completions[i]; |
|||
var className = HINT_ELEMENT_CLASS + (i != this.selectedHint ? "" : " " + ACTIVE_HINT_ELEMENT_CLASS); |
|||
if (cur.className != null) className = cur.className + " " + className; |
|||
elt.className = className; |
|||
if (i == this.selectedHint) elt.setAttribute("aria-selected", "true") |
|||
elt.id = this.id + "-" + i |
|||
elt.setAttribute("role", "option") |
|||
if (cur.render) cur.render(elt, data, cur); |
|||
else elt.appendChild(ownerDocument.createTextNode(cur.displayText || getText(cur))); |
|||
elt.hintId = i; |
|||
} |
|||
|
|||
var container = completion.options.container || ownerDocument.body; |
|||
var pos = cm.cursorCoords(completion.options.alignWithWord ? data.from : null); |
|||
var left = pos.left, top = pos.bottom, below = true; |
|||
var offsetLeft = 0, offsetTop = 0; |
|||
if (container !== ownerDocument.body) { |
|||
// We offset the cursor position because left and top are relative to the offsetParent's top left corner.
|
|||
var isContainerPositioned = ['absolute', 'relative', 'fixed'].indexOf(parentWindow.getComputedStyle(container).position) !== -1; |
|||
var offsetParent = isContainerPositioned ? container : container.offsetParent; |
|||
var offsetParentPosition = offsetParent.getBoundingClientRect(); |
|||
var bodyPosition = ownerDocument.body.getBoundingClientRect(); |
|||
offsetLeft = (offsetParentPosition.left - bodyPosition.left - offsetParent.scrollLeft); |
|||
offsetTop = (offsetParentPosition.top - bodyPosition.top - offsetParent.scrollTop); |
|||
} |
|||
hints.style.left = (left - offsetLeft) + "px"; |
|||
hints.style.top = (top - offsetTop) + "px"; |
|||
|
|||
// If we're at the edge of the screen, then we want the menu to appear on the left of the cursor.
|
|||
var winW = parentWindow.innerWidth || Math.max(ownerDocument.body.offsetWidth, ownerDocument.documentElement.offsetWidth); |
|||
var winH = parentWindow.innerHeight || Math.max(ownerDocument.body.offsetHeight, ownerDocument.documentElement.offsetHeight); |
|||
container.appendChild(hints); |
|||
cm.getInputField().setAttribute("aria-autocomplete", "list") |
|||
cm.getInputField().setAttribute("aria-owns", this.id) |
|||
cm.getInputField().setAttribute("aria-activedescendant", this.id + "-" + this.selectedHint) |
|||
|
|||
var box = completion.options.moveOnOverlap ? hints.getBoundingClientRect() : new DOMRect(); |
|||
var scrolls = completion.options.paddingForScrollbar ? hints.scrollHeight > hints.clientHeight + 1 : false; |
|||
|
|||
// Compute in the timeout to avoid reflow on init
|
|||
var startScroll; |
|||
setTimeout(function() { startScroll = cm.getScrollInfo(); }); |
|||
|
|||
var overlapY = box.bottom - winH; |
|||
if (overlapY > 0) { |
|||
var height = box.bottom - box.top, curTop = pos.top - (pos.bottom - box.top); |
|||
if (curTop - height > 0) { // Fits above cursor
|
|||
hints.style.top = (top = pos.top - height - offsetTop) + "px"; |
|||
below = false; |
|||
} else if (height > winH) { |
|||
hints.style.height = (winH - 5) + "px"; |
|||
hints.style.top = (top = pos.bottom - box.top - offsetTop) + "px"; |
|||
var cursor = cm.getCursor(); |
|||
if (data.from.ch != cursor.ch) { |
|||
pos = cm.cursorCoords(cursor); |
|||
hints.style.left = (left = pos.left - offsetLeft) + "px"; |
|||
box = hints.getBoundingClientRect(); |
|||
} |
|||
} |
|||
} |
|||
var overlapX = box.right - winW; |
|||
if (scrolls) overlapX += cm.display.nativeBarWidth; |
|||
if (overlapX > 0) { |
|||
if (box.right - box.left > winW) { |
|||
hints.style.width = (winW - 5) + "px"; |
|||
overlapX -= (box.right - box.left) - winW; |
|||
} |
|||
hints.style.left = (left = pos.left - overlapX - offsetLeft) + "px"; |
|||
} |
|||
if (scrolls) for (var node = hints.firstChild; node; node = node.nextSibling) |
|||
node.style.paddingRight = cm.display.nativeBarWidth + "px" |
|||
|
|||
cm.addKeyMap(this.keyMap = buildKeyMap(completion, { |
|||
moveFocus: function(n, avoidWrap) { widget.changeActive(widget.selectedHint + n, avoidWrap); }, |
|||
setFocus: function(n) { widget.changeActive(n); }, |
|||
menuSize: function() { return widget.screenAmount(); }, |
|||
length: completions.length, |
|||
close: function() { completion.close(); }, |
|||
pick: function() { widget.pick(); }, |
|||
data: data |
|||
})); |
|||
|
|||
if (completion.options.closeOnUnfocus) { |
|||
var closingOnBlur; |
|||
cm.on("blur", this.onBlur = function() { closingOnBlur = setTimeout(function() { completion.close(); }, 100); }); |
|||
cm.on("focus", this.onFocus = function() { clearTimeout(closingOnBlur); }); |
|||
} |
|||
|
|||
cm.on("scroll", this.onScroll = function() { |
|||
var curScroll = cm.getScrollInfo(), editor = cm.getWrapperElement().getBoundingClientRect(); |
|||
if (!startScroll) startScroll = cm.getScrollInfo(); |
|||
var newTop = top + startScroll.top - curScroll.top; |
|||
var point = newTop - (parentWindow.pageYOffset || (ownerDocument.documentElement || ownerDocument.body).scrollTop); |
|||
if (!below) point += hints.offsetHeight; |
|||
if (point <= editor.top || point >= editor.bottom) return completion.close(); |
|||
hints.style.top = newTop + "px"; |
|||
hints.style.left = (left + startScroll.left - curScroll.left) + "px"; |
|||
}); |
|||
|
|||
CodeMirror.on(hints, "dblclick", function(e) { |
|||
var t = getHintElement(hints, e.target || e.srcElement); |
|||
if (t && t.hintId != null) {widget.changeActive(t.hintId); widget.pick();} |
|||
}); |
|||
|
|||
CodeMirror.on(hints, "click", function(e) { |
|||
var t = getHintElement(hints, e.target || e.srcElement); |
|||
if (t && t.hintId != null) { |
|||
widget.changeActive(t.hintId); |
|||
if (completion.options.completeOnSingleClick) widget.pick(); |
|||
} |
|||
}); |
|||
|
|||
CodeMirror.on(hints, "mousedown", function() { |
|||
setTimeout(function(){cm.focus();}, 20); |
|||
}); |
|||
|
|||
// The first hint doesn't need to be scrolled to on init
|
|||
var selectedHintRange = this.getSelectedHintRange(); |
|||
if (selectedHintRange.from !== 0 || selectedHintRange.to !== 0) { |
|||
this.scrollToActive(); |
|||
} |
|||
|
|||
CodeMirror.signal(data, "select", completions[this.selectedHint], hints.childNodes[this.selectedHint]); |
|||
return true; |
|||
} |
|||
|
|||
Widget.prototype = { |
|||
close: function() { |
|||
if (this.completion.widget != this) return; |
|||
this.completion.widget = null; |
|||
if (this.hints.parentNode) this.hints.parentNode.removeChild(this.hints); |
|||
this.completion.cm.removeKeyMap(this.keyMap); |
|||
var input = this.completion.cm.getInputField() |
|||
input.removeAttribute("aria-activedescendant") |
|||
input.removeAttribute("aria-owns") |
|||
|
|||
var cm = this.completion.cm; |
|||
if (this.completion.options.closeOnUnfocus) { |
|||
cm.off("blur", this.onBlur); |
|||
cm.off("focus", this.onFocus); |
|||
} |
|||
cm.off("scroll", this.onScroll); |
|||
}, |
|||
|
|||
disable: function() { |
|||
this.completion.cm.removeKeyMap(this.keyMap); |
|||
var widget = this; |
|||
this.keyMap = {Enter: function() { widget.picked = true; }}; |
|||
this.completion.cm.addKeyMap(this.keyMap); |
|||
}, |
|||
|
|||
pick: function() { |
|||
this.completion.pick(this.data, this.selectedHint); |
|||
}, |
|||
|
|||
changeActive: function(i, avoidWrap) { |
|||
if (i >= this.data.list.length) |
|||
i = avoidWrap ? this.data.list.length - 1 : 0; |
|||
else if (i < 0) |
|||
i = avoidWrap ? 0 : this.data.list.length - 1; |
|||
if (this.selectedHint == i) return; |
|||
var node = this.hints.childNodes[this.selectedHint]; |
|||
if (node) { |
|||
node.className = node.className.replace(" " + ACTIVE_HINT_ELEMENT_CLASS, ""); |
|||
node.removeAttribute("aria-selected") |
|||
} |
|||
node = this.hints.childNodes[this.selectedHint = i]; |
|||
node.className += " " + ACTIVE_HINT_ELEMENT_CLASS; |
|||
node.setAttribute("aria-selected", "true") |
|||
this.completion.cm.getInputField().setAttribute("aria-activedescendant", node.id) |
|||
this.scrollToActive() |
|||
CodeMirror.signal(this.data, "select", this.data.list[this.selectedHint], node); |
|||
}, |
|||
|
|||
scrollToActive: function() { |
|||
var selectedHintRange = this.getSelectedHintRange(); |
|||
var node1 = this.hints.childNodes[selectedHintRange.from]; |
|||
var node2 = this.hints.childNodes[selectedHintRange.to]; |
|||
var firstNode = this.hints.firstChild; |
|||
if (node1.offsetTop < this.hints.scrollTop) |
|||
this.hints.scrollTop = node1.offsetTop - firstNode.offsetTop; |
|||
else if (node2.offsetTop + node2.offsetHeight > this.hints.scrollTop + this.hints.clientHeight) |
|||
this.hints.scrollTop = node2.offsetTop + node2.offsetHeight - this.hints.clientHeight + firstNode.offsetTop; |
|||
}, |
|||
|
|||
screenAmount: function() { |
|||
return Math.floor(this.hints.clientHeight / this.hints.firstChild.offsetHeight) || 1; |
|||
}, |
|||
|
|||
getSelectedHintRange: function() { |
|||
var margin = this.completion.options.scrollMargin || 0; |
|||
return { |
|||
from: Math.max(0, this.selectedHint - margin), |
|||
to: Math.min(this.data.list.length - 1, this.selectedHint + margin), |
|||
}; |
|||
} |
|||
}; |
|||
|
|||
function applicableHelpers(cm, helpers) { |
|||
if (!cm.somethingSelected()) return helpers |
|||
var result = [] |
|||
for (var i = 0; i < helpers.length; i++) |
|||
if (helpers[i].supportsSelection) result.push(helpers[i]) |
|||
return result |
|||
} |
|||
|
|||
function fetchHints(hint, cm, options, callback) { |
|||
if (hint.async) { |
|||
hint(cm, callback, options) |
|||
} else { |
|||
var result = hint(cm, options) |
|||
if (result && result.then) result.then(callback) |
|||
else callback(result) |
|||
} |
|||
} |
|||
|
|||
function resolveAutoHints(cm, pos) { |
|||
var helpers = cm.getHelpers(pos, "hint"), words |
|||
if (helpers.length) { |
|||
var resolved = function(cm, callback, options) { |
|||
var app = applicableHelpers(cm, helpers); |
|||
function run(i) { |
|||
if (i == app.length) return callback(null) |
|||
fetchHints(app[i], cm, options, function(result) { |
|||
if (result && result.list.length > 0) callback(result) |
|||
else run(i + 1) |
|||
}) |
|||
} |
|||
run(0) |
|||
} |
|||
resolved.async = true |
|||
resolved.supportsSelection = true |
|||
return resolved |
|||
} else if (words = cm.getHelper(cm.getCursor(), "hintWords")) { |
|||
return function(cm) { return CodeMirror.hint.fromList(cm, {words: words}) } |
|||
} else if (CodeMirror.hint.anyword) { |
|||
return function(cm, options) { return CodeMirror.hint.anyword(cm, options) } |
|||
} else { |
|||
return function() {} |
|||
} |
|||
} |
|||
|
|||
CodeMirror.registerHelper("hint", "auto", { |
|||
resolve: resolveAutoHints |
|||
}); |
|||
|
|||
CodeMirror.registerHelper("hint", "fromList", function(cm, options) { |
|||
var cur = cm.getCursor(), token = cm.getTokenAt(cur) |
|||
var term, from = CodeMirror.Pos(cur.line, token.start), to = cur |
|||
if (token.start < cur.ch && /\w/.test(token.string.charAt(cur.ch - token.start - 1))) { |
|||
term = token.string.substr(0, cur.ch - token.start) |
|||
} else { |
|||
term = "" |
|||
from = cur |
|||
} |
|||
var found = []; |
|||
for (var i = 0; i < options.words.length; i++) { |
|||
var word = options.words[i]; |
|||
if (word.slice(0, term.length) == term) |
|||
found.push(word); |
|||
} |
|||
|
|||
if (found.length) return {list: found, from: from, to: to}; |
|||
}); |
|||
|
|||
CodeMirror.commands.autocomplete = CodeMirror.showHint; |
|||
|
|||
var defaultOptions = { |
|||
hint: CodeMirror.hint.auto, |
|||
completeSingle: true, |
|||
alignWithWord: true, |
|||
closeCharacters: /[\s()\[\]{};:>,]/, |
|||
closeOnPick: true, |
|||
closeOnUnfocus: true, |
|||
updateOnCursorActivity: true, |
|||
completeOnSingleClick: true, |
|||
container: null, |
|||
customKeys: null, |
|||
extraKeys: null, |
|||
paddingForScrollbar: true, |
|||
moveOnOverlap: true, |
|||
}; |
|||
|
|||
CodeMirror.defineOption("hintOptions", null); |
|||
}); |
|||
@ -0,0 +1,304 @@ |
|||
// CodeMirror, copyright (c) by Marijn Haverbeke and others
|
|||
// Distributed under an MIT license: https://codemirror.net/LICENSE
|
|||
|
|||
(function(mod) { |
|||
if (typeof exports == "object" && typeof module == "object") // CommonJS
|
|||
mod(require("../../lib/codemirror"), require("../../mode/sql/sql")); |
|||
else if (typeof define == "function" && define.amd) // AMD
|
|||
define(["../../lib/codemirror", "../../mode/sql/sql"], mod); |
|||
else // Plain browser env
|
|||
mod(CodeMirror); |
|||
})(function(CodeMirror) { |
|||
"use strict"; |
|||
|
|||
var tables; |
|||
var defaultTable; |
|||
var keywords; |
|||
var identifierQuote; |
|||
var CONS = { |
|||
QUERY_DIV: ";", |
|||
ALIAS_KEYWORD: "AS" |
|||
}; |
|||
var Pos = CodeMirror.Pos, cmpPos = CodeMirror.cmpPos; |
|||
|
|||
function isArray(val) { return Object.prototype.toString.call(val) == "[object Array]" } |
|||
|
|||
function getKeywords(editor) { |
|||
var mode = editor.doc.modeOption; |
|||
if (mode === "sql") mode = "text/x-sql"; |
|||
return CodeMirror.resolveMode(mode).keywords; |
|||
} |
|||
|
|||
function getIdentifierQuote(editor) { |
|||
var mode = editor.doc.modeOption; |
|||
if (mode === "sql") mode = "text/x-sql"; |
|||
return CodeMirror.resolveMode(mode).identifierQuote || "`"; |
|||
} |
|||
|
|||
function getText(item) { |
|||
return typeof item == "string" ? item : item.text; |
|||
} |
|||
|
|||
function wrapTable(name, value) { |
|||
if (isArray(value)) value = {columns: value} |
|||
if (!value.text) value.text = name |
|||
return value |
|||
} |
|||
|
|||
function parseTables(input) { |
|||
var result = {} |
|||
if (isArray(input)) { |
|||
for (var i = input.length - 1; i >= 0; i--) { |
|||
var item = input[i] |
|||
result[getText(item).toUpperCase()] = wrapTable(getText(item), item) |
|||
} |
|||
} else if (input) { |
|||
for (var name in input) |
|||
result[name.toUpperCase()] = wrapTable(name, input[name]) |
|||
} |
|||
return result |
|||
} |
|||
|
|||
function getTable(name) { |
|||
return tables[name.toUpperCase()] |
|||
} |
|||
|
|||
function shallowClone(object) { |
|||
var result = {}; |
|||
for (var key in object) if (object.hasOwnProperty(key)) |
|||
result[key] = object[key]; |
|||
return result; |
|||
} |
|||
|
|||
function match(string, word) { |
|||
var len = string.length; |
|||
var sub = getText(word).substr(0, len); |
|||
return string.toUpperCase() === sub.toUpperCase(); |
|||
} |
|||
|
|||
function addMatches(result, search, wordlist, formatter) { |
|||
if (isArray(wordlist)) { |
|||
for (var i = 0; i < wordlist.length; i++) |
|||
if (match(search, wordlist[i])) result.push(formatter(wordlist[i])) |
|||
} else { |
|||
for (var word in wordlist) if (wordlist.hasOwnProperty(word)) { |
|||
var val = wordlist[word] |
|||
if (!val || val === true) |
|||
val = word |
|||
else |
|||
val = val.displayText ? {text: val.text, displayText: val.displayText} : val.text |
|||
if (match(search, val)) result.push(formatter(val)) |
|||
} |
|||
} |
|||
} |
|||
|
|||
function cleanName(name) { |
|||
// Get rid name from identifierQuote and preceding dot(.)
|
|||
if (name.charAt(0) == ".") { |
|||
name = name.substr(1); |
|||
} |
|||
// replace duplicated identifierQuotes with single identifierQuotes
|
|||
// and remove single identifierQuotes
|
|||
var nameParts = name.split(identifierQuote+identifierQuote); |
|||
for (var i = 0; i < nameParts.length; i++) |
|||
nameParts[i] = nameParts[i].replace(new RegExp(identifierQuote,"g"), ""); |
|||
return nameParts.join(identifierQuote); |
|||
} |
|||
|
|||
function insertIdentifierQuotes(name) { |
|||
var nameParts = getText(name).split("."); |
|||
for (var i = 0; i < nameParts.length; i++) |
|||
nameParts[i] = identifierQuote + |
|||
// duplicate identifierQuotes
|
|||
nameParts[i].replace(new RegExp(identifierQuote,"g"), identifierQuote+identifierQuote) + |
|||
identifierQuote; |
|||
var escaped = nameParts.join("."); |
|||
if (typeof name == "string") return escaped; |
|||
name = shallowClone(name); |
|||
name.text = escaped; |
|||
return name; |
|||
} |
|||
|
|||
function nameCompletion(cur, token, result, editor) { |
|||
// Try to complete table, column names and return start position of completion
|
|||
var useIdentifierQuotes = false; |
|||
var nameParts = []; |
|||
var start = token.start; |
|||
var cont = true; |
|||
while (cont) { |
|||
cont = (token.string.charAt(0) == "."); |
|||
useIdentifierQuotes = useIdentifierQuotes || (token.string.charAt(0) == identifierQuote); |
|||
|
|||
start = token.start; |
|||
nameParts.unshift(cleanName(token.string)); |
|||
|
|||
token = editor.getTokenAt(Pos(cur.line, token.start)); |
|||
if (token.string == ".") { |
|||
cont = true; |
|||
token = editor.getTokenAt(Pos(cur.line, token.start)); |
|||
} |
|||
} |
|||
|
|||
// Try to complete table names
|
|||
var string = nameParts.join("."); |
|||
addMatches(result, string, tables, function(w) { |
|||
return useIdentifierQuotes ? insertIdentifierQuotes(w) : w; |
|||
}); |
|||
|
|||
// Try to complete columns from defaultTable
|
|||
addMatches(result, string, defaultTable, function(w) { |
|||
return useIdentifierQuotes ? insertIdentifierQuotes(w) : w; |
|||
}); |
|||
|
|||
// Try to complete columns
|
|||
string = nameParts.pop(); |
|||
var table = nameParts.join("."); |
|||
|
|||
var alias = false; |
|||
var aliasTable = table; |
|||
// Check if table is available. If not, find table by Alias
|
|||
if (!getTable(table)) { |
|||
var oldTable = table; |
|||
table = findTableByAlias(table, editor); |
|||
if (table !== oldTable) alias = true; |
|||
} |
|||
|
|||
var columns = getTable(table); |
|||
if (columns && columns.columns) |
|||
columns = columns.columns; |
|||
|
|||
if (columns) { |
|||
addMatches(result, string, columns, function(w) { |
|||
var tableInsert = table; |
|||
if (alias == true) tableInsert = aliasTable; |
|||
if (typeof w == "string") { |
|||
w = tableInsert + "." + w; |
|||
} else { |
|||
w = shallowClone(w); |
|||
w.text = tableInsert + "." + w.text; |
|||
} |
|||
return useIdentifierQuotes ? insertIdentifierQuotes(w) : w; |
|||
}); |
|||
} |
|||
|
|||
return start; |
|||
} |
|||
|
|||
function eachWord(lineText, f) { |
|||
var words = lineText.split(/\s+/) |
|||
for (var i = 0; i < words.length; i++) |
|||
if (words[i]) f(words[i].replace(/[`,;]/g, '')) |
|||
} |
|||
|
|||
function findTableByAlias(alias, editor) { |
|||
var doc = editor.doc; |
|||
var fullQuery = doc.getValue(); |
|||
var aliasUpperCase = alias.toUpperCase(); |
|||
var previousWord = ""; |
|||
var table = ""; |
|||
var separator = []; |
|||
var validRange = { |
|||
start: Pos(0, 0), |
|||
end: Pos(editor.lastLine(), editor.getLineHandle(editor.lastLine()).length) |
|||
}; |
|||
|
|||
//add separator
|
|||
var indexOfSeparator = fullQuery.indexOf(CONS.QUERY_DIV); |
|||
while(indexOfSeparator != -1) { |
|||
separator.push(doc.posFromIndex(indexOfSeparator)); |
|||
indexOfSeparator = fullQuery.indexOf(CONS.QUERY_DIV, indexOfSeparator+1); |
|||
} |
|||
separator.unshift(Pos(0, 0)); |
|||
separator.push(Pos(editor.lastLine(), editor.getLineHandle(editor.lastLine()).text.length)); |
|||
|
|||
//find valid range
|
|||
var prevItem = null; |
|||
var current = editor.getCursor() |
|||
for (var i = 0; i < separator.length; i++) { |
|||
if ((prevItem == null || cmpPos(current, prevItem) > 0) && cmpPos(current, separator[i]) <= 0) { |
|||
validRange = {start: prevItem, end: separator[i]}; |
|||
break; |
|||
} |
|||
prevItem = separator[i]; |
|||
} |
|||
|
|||
if (validRange.start) { |
|||
var query = doc.getRange(validRange.start, validRange.end, false); |
|||
|
|||
for (var i = 0; i < query.length; i++) { |
|||
var lineText = query[i]; |
|||
eachWord(lineText, function(word) { |
|||
var wordUpperCase = word.toUpperCase(); |
|||
if (wordUpperCase === aliasUpperCase && getTable(previousWord)) |
|||
table = previousWord; |
|||
if (wordUpperCase !== CONS.ALIAS_KEYWORD) |
|||
previousWord = word; |
|||
}); |
|||
if (table) break; |
|||
} |
|||
} |
|||
return table; |
|||
} |
|||
|
|||
CodeMirror.registerHelper("hint", "sql", function(editor, options) { |
|||
tables = parseTables(options && options.tables) |
|||
var defaultTableName = options && options.defaultTable; |
|||
var disableKeywords = options && options.disableKeywords; |
|||
defaultTable = defaultTableName && getTable(defaultTableName); |
|||
keywords = getKeywords(editor); |
|||
identifierQuote = getIdentifierQuote(editor); |
|||
|
|||
if (defaultTableName && !defaultTable) |
|||
defaultTable = findTableByAlias(defaultTableName, editor); |
|||
|
|||
defaultTable = defaultTable || []; |
|||
|
|||
if (defaultTable.columns) |
|||
defaultTable = defaultTable.columns; |
|||
|
|||
var cur = editor.getCursor(); |
|||
var result = []; |
|||
var token = editor.getTokenAt(cur), start, end, search; |
|||
if (token.end > cur.ch) { |
|||
token.end = cur.ch; |
|||
token.string = token.string.slice(0, cur.ch - token.start); |
|||
} |
|||
|
|||
if (token.string.match(/^[.`"'\w@][\w$#]*$/g)) { |
|||
search = token.string; |
|||
start = token.start; |
|||
end = token.end; |
|||
} else { |
|||
start = end = cur.ch; |
|||
search = ""; |
|||
} |
|||
if (search.charAt(0) == "." || search.charAt(0) == identifierQuote) { |
|||
start = nameCompletion(cur, token, result, editor); |
|||
} else { |
|||
var objectOrClass = function(w, className) { |
|||
if (typeof w === "object") { |
|||
w.className = className; |
|||
} else { |
|||
w = { text: w, className: className }; |
|||
} |
|||
return w; |
|||
}; |
|||
addMatches(result, search, defaultTable, function(w) { |
|||
return objectOrClass(w, "CodeMirror-hint-table CodeMirror-hint-default-table"); |
|||
}); |
|||
addMatches( |
|||
result, |
|||
search, |
|||
tables, function(w) { |
|||
return objectOrClass(w, "CodeMirror-hint-table"); |
|||
} |
|||
); |
|||
if (!disableKeywords) |
|||
addMatches(result, search, keywords, function(w) { |
|||
return objectOrClass(w.toUpperCase(), "CodeMirror-hint-keyword"); |
|||
}); |
|||
} |
|||
|
|||
return {list: result, from: Pos(cur.line, start), to: Pos(cur.line, end)}; |
|||
}); |
|||
}); |
|||
@ -0,0 +1,132 @@ |
|||
// CodeMirror, copyright (c) by Marijn Haverbeke and others
|
|||
// Distributed under an MIT license: https://codemirror.net/LICENSE
|
|||
|
|||
(function(mod) { |
|||
if (typeof exports == "object" && typeof module == "object") // CommonJS
|
|||
mod(require("../../lib/codemirror")); |
|||
else if (typeof define == "function" && define.amd) // AMD
|
|||
define(["../../lib/codemirror"], mod); |
|||
else // Plain browser env
|
|||
mod(CodeMirror); |
|||
})(function(CodeMirror) { |
|||
"use strict"; |
|||
|
|||
var Pos = CodeMirror.Pos; |
|||
|
|||
function matches(hint, typed, matchInMiddle) { |
|||
if (matchInMiddle) return hint.indexOf(typed) >= 0; |
|||
else return hint.lastIndexOf(typed, 0) == 0; |
|||
} |
|||
|
|||
function getHints(cm, options) { |
|||
var tags = options && options.schemaInfo; |
|||
var quote = (options && options.quoteChar) || '"'; |
|||
var matchInMiddle = options && options.matchInMiddle; |
|||
if (!tags) return; |
|||
var cur = cm.getCursor(), token = cm.getTokenAt(cur); |
|||
if (token.end > cur.ch) { |
|||
token.end = cur.ch; |
|||
token.string = token.string.slice(0, cur.ch - token.start); |
|||
} |
|||
var inner = CodeMirror.innerMode(cm.getMode(), token.state); |
|||
if (!inner.mode.xmlCurrentTag) return |
|||
var result = [], replaceToken = false, prefix; |
|||
var tag = /\btag\b/.test(token.type) && !/>$/.test(token.string); |
|||
var tagName = tag && /^\w/.test(token.string), tagStart; |
|||
|
|||
if (tagName) { |
|||
var before = cm.getLine(cur.line).slice(Math.max(0, token.start - 2), token.start); |
|||
var tagType = /<\/$/.test(before) ? "close" : /<$/.test(before) ? "open" : null; |
|||
if (tagType) tagStart = token.start - (tagType == "close" ? 2 : 1); |
|||
} else if (tag && token.string == "<") { |
|||
tagType = "open"; |
|||
} else if (tag && token.string == "</") { |
|||
tagType = "close"; |
|||
} |
|||
|
|||
var tagInfo = inner.mode.xmlCurrentTag(inner.state) |
|||
if (!tag && !tagInfo || tagType) { |
|||
if (tagName) |
|||
prefix = token.string; |
|||
replaceToken = tagType; |
|||
var context = inner.mode.xmlCurrentContext ? inner.mode.xmlCurrentContext(inner.state) : [] |
|||
var inner = context.length && context[context.length - 1] |
|||
var curTag = inner && tags[inner] |
|||
var childList = inner ? curTag && curTag.children : tags["!top"]; |
|||
if (childList && tagType != "close") { |
|||
for (var i = 0; i < childList.length; ++i) if (!prefix || matches(childList[i], prefix, matchInMiddle)) |
|||
result.push("<" + childList[i]); |
|||
} else if (tagType != "close") { |
|||
for (var name in tags) |
|||
if (tags.hasOwnProperty(name) && name != "!top" && name != "!attrs" && (!prefix || matches(name, prefix, matchInMiddle))) |
|||
result.push("<" + name); |
|||
} |
|||
if (inner && (!prefix || tagType == "close" && matches(inner, prefix, matchInMiddle))) |
|||
result.push("</" + inner + ">"); |
|||
} else { |
|||
// Attribute completion
|
|||
var curTag = tagInfo && tags[tagInfo.name], attrs = curTag && curTag.attrs; |
|||
var globalAttrs = tags["!attrs"]; |
|||
if (!attrs && !globalAttrs) return; |
|||
if (!attrs) { |
|||
attrs = globalAttrs; |
|||
} else if (globalAttrs) { // Combine tag-local and global attributes
|
|||
var set = {}; |
|||
for (var nm in globalAttrs) if (globalAttrs.hasOwnProperty(nm)) set[nm] = globalAttrs[nm]; |
|||
for (var nm in attrs) if (attrs.hasOwnProperty(nm)) set[nm] = attrs[nm]; |
|||
attrs = set; |
|||
} |
|||
if (token.type == "string" || token.string == "=") { // A value
|
|||
var before = cm.getRange(Pos(cur.line, Math.max(0, cur.ch - 60)), |
|||
Pos(cur.line, token.type == "string" ? token.start : token.end)); |
|||
var atName = before.match(/([^\s\u00a0=<>\"\']+)=$/), atValues; |
|||
if (!atName || !attrs.hasOwnProperty(atName[1]) || !(atValues = attrs[atName[1]])) return; |
|||
if (typeof atValues == 'function') atValues = atValues.call(this, cm); // Functions can be used to supply values for autocomplete widget
|
|||
if (token.type == "string") { |
|||
prefix = token.string; |
|||
var n = 0; |
|||
if (/['"]/.test(token.string.charAt(0))) { |
|||
quote = token.string.charAt(0); |
|||
prefix = token.string.slice(1); |
|||
n++; |
|||
} |
|||
var len = token.string.length; |
|||
if (/['"]/.test(token.string.charAt(len - 1))) { |
|||
quote = token.string.charAt(len - 1); |
|||
prefix = token.string.substr(n, len - 2); |
|||
} |
|||
if (n) { // an opening quote
|
|||
var line = cm.getLine(cur.line); |
|||
if (line.length > token.end && line.charAt(token.end) == quote) token.end++; // include a closing quote
|
|||
} |
|||
replaceToken = true; |
|||
} |
|||
var returnHintsFromAtValues = function(atValues) { |
|||
if (atValues) |
|||
for (var i = 0; i < atValues.length; ++i) if (!prefix || matches(atValues[i], prefix, matchInMiddle)) |
|||
result.push(quote + atValues[i] + quote); |
|||
return returnHints(); |
|||
}; |
|||
if (atValues && atValues.then) return atValues.then(returnHintsFromAtValues); |
|||
return returnHintsFromAtValues(atValues); |
|||
} else { // An attribute name
|
|||
if (token.type == "attribute") { |
|||
prefix = token.string; |
|||
replaceToken = true; |
|||
} |
|||
for (var attr in attrs) if (attrs.hasOwnProperty(attr) && (!prefix || matches(attr, prefix, matchInMiddle))) |
|||
result.push(attr); |
|||
} |
|||
} |
|||
function returnHints() { |
|||
return { |
|||
list: result, |
|||
from: replaceToken ? Pos(cur.line, tagStart == null ? token.start : tagStart) : cur, |
|||
to: replaceToken ? Pos(cur.line, token.end) : cur |
|||
}; |
|||
} |
|||
return returnHints(); |
|||
} |
|||
|
|||
CodeMirror.registerHelper("hint", "xml", getHints); |
|||
}); |
|||
@ -0,0 +1,47 @@ |
|||
// CodeMirror, copyright (c) by Marijn Haverbeke and others
|
|||
// Distributed under an MIT license: https://codemirror.net/LICENSE
|
|||
|
|||
// Depends on coffeelint.js from http://www.coffeelint.org/js/coffeelint.js
|
|||
|
|||
// declare global: coffeelint
|
|||
|
|||
(function(mod) { |
|||
if (typeof exports == "object" && typeof module == "object") // CommonJS
|
|||
mod(require("../../lib/codemirror")); |
|||
else if (typeof define == "function" && define.amd) // AMD
|
|||
define(["../../lib/codemirror"], mod); |
|||
else // Plain browser env
|
|||
mod(CodeMirror); |
|||
})(function(CodeMirror) { |
|||
"use strict"; |
|||
|
|||
CodeMirror.registerHelper("lint", "coffeescript", function(text) { |
|||
var found = []; |
|||
if (!window.coffeelint) { |
|||
if (window.console) { |
|||
window.console.error("Error: window.coffeelint not defined, CodeMirror CoffeeScript linting cannot run."); |
|||
} |
|||
return found; |
|||
} |
|||
var parseError = function(err) { |
|||
var loc = err.lineNumber; |
|||
found.push({from: CodeMirror.Pos(loc-1, 0), |
|||
to: CodeMirror.Pos(loc, 0), |
|||
severity: err.level, |
|||
message: err.message}); |
|||
}; |
|||
try { |
|||
var res = coffeelint.lint(text); |
|||
for(var i = 0; i < res.length; i++) { |
|||
parseError(res[i]); |
|||
} |
|||
} catch(e) { |
|||
found.push({from: CodeMirror.Pos(e.location.first_line, 0), |
|||
to: CodeMirror.Pos(e.location.last_line, e.location.last_column), |
|||
severity: 'error', |
|||
message: e.message}); |
|||
} |
|||
return found; |
|||
}); |
|||
|
|||
}); |
|||
@ -0,0 +1,40 @@ |
|||
// CodeMirror, copyright (c) by Marijn Haverbeke and others
|
|||
// Distributed under an MIT license: https://codemirror.net/LICENSE
|
|||
|
|||
// Depends on csslint.js from https://github.com/stubbornella/csslint
|
|||
|
|||
// declare global: CSSLint
|
|||
|
|||
(function(mod) { |
|||
if (typeof exports == "object" && typeof module == "object") // CommonJS
|
|||
mod(require("../../lib/codemirror")); |
|||
else if (typeof define == "function" && define.amd) // AMD
|
|||
define(["../../lib/codemirror"], mod); |
|||
else // Plain browser env
|
|||
mod(CodeMirror); |
|||
})(function(CodeMirror) { |
|||
"use strict"; |
|||
|
|||
CodeMirror.registerHelper("lint", "css", function(text, options) { |
|||
var found = []; |
|||
if (!window.CSSLint) { |
|||
if (window.console) { |
|||
window.console.error("Error: window.CSSLint not defined, CodeMirror CSS linting cannot run."); |
|||
} |
|||
return found; |
|||
} |
|||
var results = CSSLint.verify(text, options), messages = results.messages, message = null; |
|||
for ( var i = 0; i < messages.length; i++) { |
|||
message = messages[i]; |
|||
var startLine = message.line -1, endLine = message.line -1, startCol = message.col -1, endCol = message.col; |
|||
found.push({ |
|||
from: CodeMirror.Pos(startLine, startCol), |
|||
to: CodeMirror.Pos(endLine, endCol), |
|||
message: message.message, |
|||
severity : message.type |
|||
}); |
|||
} |
|||
return found; |
|||
}); |
|||
|
|||
}); |
|||
@ -0,0 +1,59 @@ |
|||
// CodeMirror, copyright (c) by Marijn Haverbeke and others
|
|||
// Distributed under an MIT license: https://codemirror.net/LICENSE
|
|||
|
|||
// Depends on htmlhint.js from http://htmlhint.com/js/htmlhint.js
|
|||
|
|||
// declare global: HTMLHint
|
|||
|
|||
(function(mod) { |
|||
if (typeof exports == "object" && typeof module == "object") // CommonJS
|
|||
mod(require("../../lib/codemirror"), require("htmlhint")); |
|||
else if (typeof define == "function" && define.amd) // AMD
|
|||
define(["../../lib/codemirror", "htmlhint"], mod); |
|||
else // Plain browser env
|
|||
mod(CodeMirror, window.HTMLHint); |
|||
})(function(CodeMirror, HTMLHint) { |
|||
"use strict"; |
|||
|
|||
var defaultRules = { |
|||
"tagname-lowercase": true, |
|||
"attr-lowercase": true, |
|||
"attr-value-double-quotes": true, |
|||
"doctype-first": false, |
|||
"tag-pair": true, |
|||
"spec-char-escape": true, |
|||
"id-unique": true, |
|||
"src-not-empty": true, |
|||
"attr-no-duplication": true |
|||
}; |
|||
|
|||
CodeMirror.registerHelper("lint", "html", function(text, options) { |
|||
var found = []; |
|||
if (HTMLHint && !HTMLHint.verify) { |
|||
if(typeof HTMLHint.default !== 'undefined') { |
|||
HTMLHint = HTMLHint.default; |
|||
} else { |
|||
HTMLHint = HTMLHint.HTMLHint; |
|||
} |
|||
} |
|||
if (!HTMLHint) HTMLHint = window.HTMLHint; |
|||
if (!HTMLHint) { |
|||
if (window.console) { |
|||
window.console.error("Error: HTMLHint not found, not defined on window, or not available through define/require, CodeMirror HTML linting cannot run."); |
|||
} |
|||
return found; |
|||
} |
|||
var messages = HTMLHint.verify(text, options && options.rules || defaultRules); |
|||
for (var i = 0; i < messages.length; i++) { |
|||
var message = messages[i]; |
|||
var startLine = message.line - 1, endLine = message.line - 1, startCol = message.col - 1, endCol = message.col; |
|||
found.push({ |
|||
from: CodeMirror.Pos(startLine, startCol), |
|||
to: CodeMirror.Pos(endLine, endCol), |
|||
message: message.message, |
|||
severity : message.type |
|||
}); |
|||
} |
|||
return found; |
|||
}); |
|||
}); |
|||
@ -0,0 +1,65 @@ |
|||
// CodeMirror, copyright (c) by Marijn Haverbeke and others
|
|||
// Distributed under an MIT license: https://codemirror.net/LICENSE
|
|||
|
|||
// Depends on jshint.js from https://github.com/jshint/jshint
|
|||
|
|||
(function(mod) { |
|||
if (typeof exports == "object" && typeof module == "object") // CommonJS
|
|||
mod(require("../../lib/codemirror")); |
|||
else if (typeof define == "function" && define.amd) // AMD
|
|||
define(["../../lib/codemirror"], mod); |
|||
else // Plain browser env
|
|||
mod(CodeMirror); |
|||
})(function(CodeMirror) { |
|||
"use strict"; |
|||
// declare global: JSHINT
|
|||
|
|||
function validator(text, options) { |
|||
if (!window.JSHINT) { |
|||
if (window.console) { |
|||
window.console.error("Error: window.JSHINT not defined, CodeMirror JavaScript linting cannot run."); |
|||
} |
|||
return []; |
|||
} |
|||
if (!options.indent) // JSHint error.character actually is a column index, this fixes underlining on lines using tabs for indentation
|
|||
options.indent = 1; // JSHint default value is 4
|
|||
JSHINT(text, options, options.globals); |
|||
var errors = JSHINT.data().errors, result = []; |
|||
if (errors) parseErrors(errors, result); |
|||
return result; |
|||
} |
|||
|
|||
CodeMirror.registerHelper("lint", "javascript", validator); |
|||
|
|||
function parseErrors(errors, output) { |
|||
for ( var i = 0; i < errors.length; i++) { |
|||
var error = errors[i]; |
|||
if (error) { |
|||
if (error.line <= 0) { |
|||
if (window.console) { |
|||
window.console.warn("Cannot display JSHint error (invalid line " + error.line + ")", error); |
|||
} |
|||
continue; |
|||
} |
|||
|
|||
var start = error.character - 1, end = start + 1; |
|||
if (error.evidence) { |
|||
var index = error.evidence.substring(start).search(/.\b/); |
|||
if (index > -1) { |
|||
end += index; |
|||
} |
|||
} |
|||
|
|||
// Convert to format expected by validation service
|
|||
var hint = { |
|||
message: error.reason, |
|||
severity: error.code ? (error.code.startsWith('W') ? "warning" : "error") : "error", |
|||
from: CodeMirror.Pos(error.line - 1, start), |
|||
to: CodeMirror.Pos(error.line - 1, end) |
|||
}; |
|||
|
|||
output.push(hint); |
|||
} |
|||
} |
|||
} |
|||
}); |
|||
@ -0,0 +1,40 @@ |
|||
// CodeMirror, copyright (c) by Marijn Haverbeke and others
|
|||
// Distributed under an MIT license: https://codemirror.net/LICENSE
|
|||
|
|||
// Depends on jsonlint.js from https://github.com/zaach/jsonlint
|
|||
|
|||
// declare global: jsonlint
|
|||
|
|||
(function(mod) { |
|||
if (typeof exports == "object" && typeof module == "object") // CommonJS
|
|||
mod(require("../../lib/codemirror")); |
|||
else if (typeof define == "function" && define.amd) // AMD
|
|||
define(["../../lib/codemirror"], mod); |
|||
else // Plain browser env
|
|||
mod(CodeMirror); |
|||
})(function(CodeMirror) { |
|||
"use strict"; |
|||
|
|||
CodeMirror.registerHelper("lint", "json", function(text) { |
|||
var found = []; |
|||
if (!window.jsonlint) { |
|||
if (window.console) { |
|||
window.console.error("Error: window.jsonlint not defined, CodeMirror JSON linting cannot run."); |
|||
} |
|||
return found; |
|||
} |
|||
// for jsonlint's web dist jsonlint is exported as an object with a single property parser, of which parseError
|
|||
// is a subproperty
|
|||
var jsonlint = window.jsonlint.parser || window.jsonlint |
|||
jsonlint.parseError = function(str, hash) { |
|||
var loc = hash.loc; |
|||
found.push({from: CodeMirror.Pos(loc.first_line - 1, loc.first_column), |
|||
to: CodeMirror.Pos(loc.last_line - 1, loc.last_column), |
|||
message: str}); |
|||
}; |
|||
try { jsonlint.parse(text); } |
|||
catch(e) {} |
|||
return found; |
|||
}); |
|||
|
|||
}); |
|||
@ -0,0 +1,79 @@ |
|||
/* The lint marker gutter */ |
|||
.CodeMirror-lint-markers { |
|||
width: 16px; |
|||
} |
|||
|
|||
.CodeMirror-lint-tooltip { |
|||
background-color: #ffd; |
|||
border: 1px solid black; |
|||
border-radius: 4px 4px 4px 4px; |
|||
color: black; |
|||
font-family: monospace; |
|||
font-size: 10pt; |
|||
overflow: hidden; |
|||
padding: 2px 5px; |
|||
position: fixed; |
|||
white-space: pre; |
|||
white-space: pre-wrap; |
|||
z-index: 100; |
|||
max-width: 600px; |
|||
opacity: 0; |
|||
transition: opacity .4s; |
|||
-moz-transition: opacity .4s; |
|||
-webkit-transition: opacity .4s; |
|||
-o-transition: opacity .4s; |
|||
-ms-transition: opacity .4s; |
|||
} |
|||
|
|||
.CodeMirror-lint-mark { |
|||
background-position: left bottom; |
|||
background-repeat: repeat-x; |
|||
} |
|||
|
|||
.CodeMirror-lint-mark-warning { |
|||
background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAQAAAADCAYAAAC09K7GAAAAAXNSR0IArs4c6QAAAAZiS0dEAP8A/wD/oL2nkwAAAAlwSFlzAAALEwAACxMBAJqcGAAAAAd0SU1FB9sJFhQXEbhTg7YAAAAZdEVYdENvbW1lbnQAQ3JlYXRlZCB3aXRoIEdJTVBXgQ4XAAAAMklEQVQI12NkgIIvJ3QXMjAwdDN+OaEbysDA4MPAwNDNwMCwiOHLCd1zX07o6kBVGQEAKBANtobskNMAAAAASUVORK5CYII="); |
|||
} |
|||
|
|||
.CodeMirror-lint-mark-error { |
|||
background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAQAAAADCAYAAAC09K7GAAAAAXNSR0IArs4c6QAAAAZiS0dEAP8A/wD/oL2nkwAAAAlwSFlzAAALEwAACxMBAJqcGAAAAAd0SU1FB9sJDw4cOCW1/KIAAAAZdEVYdENvbW1lbnQAQ3JlYXRlZCB3aXRoIEdJTVBXgQ4XAAAAHElEQVQI12NggIL/DAz/GdA5/xkY/qPKMDAwAADLZwf5rvm+LQAAAABJRU5ErkJggg=="); |
|||
} |
|||
|
|||
.CodeMirror-lint-marker { |
|||
background-position: center center; |
|||
background-repeat: no-repeat; |
|||
cursor: pointer; |
|||
display: inline-block; |
|||
height: 16px; |
|||
width: 16px; |
|||
vertical-align: middle; |
|||
position: relative; |
|||
} |
|||
|
|||
.CodeMirror-lint-message { |
|||
padding-left: 18px; |
|||
background-position: top left; |
|||
background-repeat: no-repeat; |
|||
} |
|||
|
|||
.CodeMirror-lint-marker-warning, .CodeMirror-lint-message-warning { |
|||
background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAAANlBMVEX/uwDvrwD/uwD/uwD/uwD/uwD/uwD/uwD/uwD6twD/uwAAAADurwD2tQD7uAD+ugAAAAD/uwDhmeTRAAAADHRSTlMJ8mN1EYcbmiixgACm7WbuAAAAVklEQVR42n3PUQqAIBBFUU1LLc3u/jdbOJoW1P08DA9Gba8+YWJ6gNJoNYIBzAA2chBth5kLmG9YUoG0NHAUwFXwO9LuBQL1giCQb8gC9Oro2vp5rncCIY8L8uEx5ZkAAAAASUVORK5CYII="); |
|||
} |
|||
|
|||
.CodeMirror-lint-marker-error, .CodeMirror-lint-message-error { |
|||
background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAAAHlBMVEW7AAC7AACxAAC7AAC7AAAAAAC4AAC5AAD///+7AAAUdclpAAAABnRSTlMXnORSiwCK0ZKSAAAATUlEQVR42mWPOQ7AQAgDuQLx/z8csYRmPRIFIwRGnosRrpamvkKi0FTIiMASR3hhKW+hAN6/tIWhu9PDWiTGNEkTtIOucA5Oyr9ckPgAWm0GPBog6v4AAAAASUVORK5CYII="); |
|||
} |
|||
|
|||
.CodeMirror-lint-marker-multiple { |
|||
background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAcAAAAHCAMAAADzjKfhAAAACVBMVEUAAAAAAAC/v7914kyHAAAAAXRSTlMAQObYZgAAACNJREFUeNo1ioEJAAAIwmz/H90iFFSGJgFMe3gaLZ0od+9/AQZ0ADosbYraAAAAAElFTkSuQmCC"); |
|||
background-repeat: no-repeat; |
|||
background-position: right bottom; |
|||
width: 100%; height: 100%; |
|||
} |
|||
|
|||
.CodeMirror-lint-line-error { |
|||
background-color: rgba(183, 76, 81, 0.08); |
|||
} |
|||
|
|||
.CodeMirror-lint-line-warning { |
|||
background-color: rgba(255, 211, 0, 0.1); |
|||
} |
|||
@ -0,0 +1,291 @@ |
|||
// CodeMirror, copyright (c) by Marijn Haverbeke and others
|
|||
// Distributed under an MIT license: https://codemirror.net/LICENSE
|
|||
|
|||
(function(mod) { |
|||
if (typeof exports == "object" && typeof module == "object") // CommonJS
|
|||
mod(require("../../lib/codemirror")); |
|||
else if (typeof define == "function" && define.amd) // AMD
|
|||
define(["../../lib/codemirror"], mod); |
|||
else // Plain browser env
|
|||
mod(CodeMirror); |
|||
})(function(CodeMirror) { |
|||
"use strict"; |
|||
var GUTTER_ID = "CodeMirror-lint-markers"; |
|||
var LINT_LINE_ID = "CodeMirror-lint-line-"; |
|||
|
|||
function showTooltip(cm, e, content) { |
|||
var tt = document.createElement("div"); |
|||
tt.className = "CodeMirror-lint-tooltip cm-s-" + cm.options.theme; |
|||
tt.appendChild(content.cloneNode(true)); |
|||
if (cm.state.lint.options.selfContain) |
|||
cm.getWrapperElement().appendChild(tt); |
|||
else |
|||
document.body.appendChild(tt); |
|||
|
|||
function position(e) { |
|||
if (!tt.parentNode) return CodeMirror.off(document, "mousemove", position); |
|||
tt.style.top = Math.max(0, e.clientY - tt.offsetHeight - 5) + "px"; |
|||
tt.style.left = (e.clientX + 5) + "px"; |
|||
} |
|||
CodeMirror.on(document, "mousemove", position); |
|||
position(e); |
|||
if (tt.style.opacity != null) tt.style.opacity = 1; |
|||
return tt; |
|||
} |
|||
function rm(elt) { |
|||
if (elt.parentNode) elt.parentNode.removeChild(elt); |
|||
} |
|||
function hideTooltip(tt) { |
|||
if (!tt.parentNode) return; |
|||
if (tt.style.opacity == null) rm(tt); |
|||
tt.style.opacity = 0; |
|||
setTimeout(function() { rm(tt); }, 600); |
|||
} |
|||
|
|||
function showTooltipFor(cm, e, content, node) { |
|||
var tooltip = showTooltip(cm, e, content); |
|||
function hide() { |
|||
CodeMirror.off(node, "mouseout", hide); |
|||
if (tooltip) { hideTooltip(tooltip); tooltip = null; } |
|||
} |
|||
var poll = setInterval(function() { |
|||
if (tooltip) for (var n = node;; n = n.parentNode) { |
|||
if (n && n.nodeType == 11) n = n.host; |
|||
if (n == document.body) return; |
|||
if (!n) { hide(); break; } |
|||
} |
|||
if (!tooltip) return clearInterval(poll); |
|||
}, 400); |
|||
CodeMirror.on(node, "mouseout", hide); |
|||
} |
|||
|
|||
function LintState(cm, conf, hasGutter) { |
|||
this.marked = []; |
|||
if (conf instanceof Function) conf = {getAnnotations: conf}; |
|||
if (!conf || conf === true) conf = {}; |
|||
this.options = {}; |
|||
this.linterOptions = conf.options || {}; |
|||
for (var prop in defaults) this.options[prop] = defaults[prop]; |
|||
for (var prop in conf) { |
|||
if (defaults.hasOwnProperty(prop)) { |
|||
if (conf[prop] != null) this.options[prop] = conf[prop]; |
|||
} else if (!conf.options) { |
|||
this.linterOptions[prop] = conf[prop]; |
|||
} |
|||
} |
|||
this.timeout = null; |
|||
this.hasGutter = hasGutter; |
|||
this.onMouseOver = function(e) { onMouseOver(cm, e); }; |
|||
this.waitingFor = 0 |
|||
} |
|||
|
|||
var defaults = { |
|||
highlightLines: false, |
|||
tooltips: true, |
|||
delay: 500, |
|||
lintOnChange: true, |
|||
getAnnotations: null, |
|||
async: false, |
|||
selfContain: null, |
|||
formatAnnotation: null, |
|||
onUpdateLinting: null |
|||
} |
|||
|
|||
function clearMarks(cm) { |
|||
var state = cm.state.lint; |
|||
if (state.hasGutter) cm.clearGutter(GUTTER_ID); |
|||
if (state.options.highlightLines) clearErrorLines(cm); |
|||
for (var i = 0; i < state.marked.length; ++i) |
|||
state.marked[i].clear(); |
|||
state.marked.length = 0; |
|||
} |
|||
|
|||
function clearErrorLines(cm) { |
|||
cm.eachLine(function(line) { |
|||
var has = line.wrapClass && /\bCodeMirror-lint-line-\w+\b/.exec(line.wrapClass); |
|||
if (has) cm.removeLineClass(line, "wrap", has[0]); |
|||
}) |
|||
} |
|||
|
|||
function makeMarker(cm, labels, severity, multiple, tooltips) { |
|||
var marker = document.createElement("div"), inner = marker; |
|||
marker.className = "CodeMirror-lint-marker CodeMirror-lint-marker-" + severity; |
|||
if (multiple) { |
|||
inner = marker.appendChild(document.createElement("div")); |
|||
inner.className = "CodeMirror-lint-marker CodeMirror-lint-marker-multiple"; |
|||
} |
|||
|
|||
if (tooltips != false) CodeMirror.on(inner, "mouseover", function(e) { |
|||
showTooltipFor(cm, e, labels, inner); |
|||
}); |
|||
|
|||
return marker; |
|||
} |
|||
|
|||
function getMaxSeverity(a, b) { |
|||
if (a == "error") return a; |
|||
else return b; |
|||
} |
|||
|
|||
function groupByLine(annotations) { |
|||
var lines = []; |
|||
for (var i = 0; i < annotations.length; ++i) { |
|||
var ann = annotations[i], line = ann.from.line; |
|||
(lines[line] || (lines[line] = [])).push(ann); |
|||
} |
|||
return lines; |
|||
} |
|||
|
|||
function annotationTooltip(ann) { |
|||
var severity = ann.severity; |
|||
if (!severity) severity = "error"; |
|||
var tip = document.createElement("div"); |
|||
tip.className = "CodeMirror-lint-message CodeMirror-lint-message-" + severity; |
|||
if (typeof ann.messageHTML != 'undefined') { |
|||
tip.innerHTML = ann.messageHTML; |
|||
} else { |
|||
tip.appendChild(document.createTextNode(ann.message)); |
|||
} |
|||
return tip; |
|||
} |
|||
|
|||
function lintAsync(cm, getAnnotations) { |
|||
var state = cm.state.lint |
|||
var id = ++state.waitingFor |
|||
function abort() { |
|||
id = -1 |
|||
cm.off("change", abort) |
|||
} |
|||
cm.on("change", abort) |
|||
getAnnotations(cm.getValue(), function(annotations, arg2) { |
|||
cm.off("change", abort) |
|||
if (state.waitingFor != id) return |
|||
if (arg2 && annotations instanceof CodeMirror) annotations = arg2 |
|||
cm.operation(function() {updateLinting(cm, annotations)}) |
|||
}, state.linterOptions, cm); |
|||
} |
|||
|
|||
function startLinting(cm) { |
|||
var state = cm.state.lint; |
|||
if (!state) return; |
|||
var options = state.options; |
|||
/* |
|||
* Passing rules in `options` property prevents JSHint (and other linters) from complaining |
|||
* about unrecognized rules like `onUpdateLinting`, `delay`, `lintOnChange`, etc. |
|||
*/ |
|||
var getAnnotations = options.getAnnotations || cm.getHelper(CodeMirror.Pos(0, 0), "lint"); |
|||
if (!getAnnotations) return; |
|||
if (options.async || getAnnotations.async) { |
|||
lintAsync(cm, getAnnotations) |
|||
} else { |
|||
var annotations = getAnnotations(cm.getValue(), state.linterOptions, cm); |
|||
if (!annotations) return; |
|||
if (annotations.then) annotations.then(function(issues) { |
|||
cm.operation(function() {updateLinting(cm, issues)}) |
|||
}); |
|||
else cm.operation(function() {updateLinting(cm, annotations)}) |
|||
} |
|||
} |
|||
|
|||
function updateLinting(cm, annotationsNotSorted) { |
|||
var state = cm.state.lint; |
|||
if (!state) return; |
|||
var options = state.options; |
|||
clearMarks(cm); |
|||
|
|||
var annotations = groupByLine(annotationsNotSorted); |
|||
|
|||
for (var line = 0; line < annotations.length; ++line) { |
|||
var anns = annotations[line]; |
|||
if (!anns) continue; |
|||
|
|||
// filter out duplicate messages
|
|||
var message = []; |
|||
anns = anns.filter(function(item) { return message.indexOf(item.message) > -1 ? false : message.push(item.message) }); |
|||
|
|||
var maxSeverity = null; |
|||
var tipLabel = state.hasGutter && document.createDocumentFragment(); |
|||
|
|||
for (var i = 0; i < anns.length; ++i) { |
|||
var ann = anns[i]; |
|||
var severity = ann.severity; |
|||
if (!severity) severity = "error"; |
|||
maxSeverity = getMaxSeverity(maxSeverity, severity); |
|||
|
|||
if (options.formatAnnotation) ann = options.formatAnnotation(ann); |
|||
if (state.hasGutter) tipLabel.appendChild(annotationTooltip(ann)); |
|||
|
|||
if (ann.to) state.marked.push(cm.markText(ann.from, ann.to, { |
|||
className: "CodeMirror-lint-mark CodeMirror-lint-mark-" + severity, |
|||
__annotation: ann |
|||
})); |
|||
} |
|||
// use original annotations[line] to show multiple messages
|
|||
if (state.hasGutter) |
|||
cm.setGutterMarker(line, GUTTER_ID, makeMarker(cm, tipLabel, maxSeverity, annotations[line].length > 1, |
|||
options.tooltips)); |
|||
|
|||
if (options.highlightLines) |
|||
cm.addLineClass(line, "wrap", LINT_LINE_ID + maxSeverity); |
|||
} |
|||
if (options.onUpdateLinting) options.onUpdateLinting(annotationsNotSorted, annotations, cm); |
|||
} |
|||
|
|||
function onChange(cm) { |
|||
var state = cm.state.lint; |
|||
if (!state) return; |
|||
clearTimeout(state.timeout); |
|||
state.timeout = setTimeout(function(){startLinting(cm);}, state.options.delay); |
|||
} |
|||
|
|||
function popupTooltips(cm, annotations, e) { |
|||
var target = e.target || e.srcElement; |
|||
var tooltip = document.createDocumentFragment(); |
|||
for (var i = 0; i < annotations.length; i++) { |
|||
var ann = annotations[i]; |
|||
tooltip.appendChild(annotationTooltip(ann)); |
|||
} |
|||
showTooltipFor(cm, e, tooltip, target); |
|||
} |
|||
|
|||
function onMouseOver(cm, e) { |
|||
var target = e.target || e.srcElement; |
|||
if (!/\bCodeMirror-lint-mark-/.test(target.className)) return; |
|||
var box = target.getBoundingClientRect(), x = (box.left + box.right) / 2, y = (box.top + box.bottom) / 2; |
|||
var spans = cm.findMarksAt(cm.coordsChar({left: x, top: y}, "client")); |
|||
|
|||
var annotations = []; |
|||
for (var i = 0; i < spans.length; ++i) { |
|||
var ann = spans[i].__annotation; |
|||
if (ann) annotations.push(ann); |
|||
} |
|||
if (annotations.length) popupTooltips(cm, annotations, e); |
|||
} |
|||
|
|||
CodeMirror.defineOption("lint", false, function(cm, val, old) { |
|||
if (old && old != CodeMirror.Init) { |
|||
clearMarks(cm); |
|||
if (cm.state.lint.options.lintOnChange !== false) |
|||
cm.off("change", onChange); |
|||
CodeMirror.off(cm.getWrapperElement(), "mouseover", cm.state.lint.onMouseOver); |
|||
clearTimeout(cm.state.lint.timeout); |
|||
delete cm.state.lint; |
|||
} |
|||
|
|||
if (val) { |
|||
var gutters = cm.getOption("gutters"), hasLintGutter = false; |
|||
for (var i = 0; i < gutters.length; ++i) if (gutters[i] == GUTTER_ID) hasLintGutter = true; |
|||
var state = cm.state.lint = new LintState(cm, val, hasLintGutter); |
|||
if (state.options.lintOnChange) |
|||
cm.on("change", onChange); |
|||
if (state.options.tooltips != false && state.options.tooltips != "gutter") |
|||
CodeMirror.on(cm.getWrapperElement(), "mouseover", state.onMouseOver); |
|||
|
|||
startLinting(cm); |
|||
} |
|||
}); |
|||
|
|||
CodeMirror.defineExtension("performLint", function() { |
|||
startLinting(this); |
|||
}); |
|||
}); |
|||
@ -0,0 +1,41 @@ |
|||
// CodeMirror, copyright (c) by Marijn Haverbeke and others
|
|||
// Distributed under an MIT license: https://codemirror.net/LICENSE
|
|||
|
|||
(function(mod) { |
|||
if (typeof exports == "object" && typeof module == "object") // CommonJS
|
|||
mod(require("../../lib/codemirror")); |
|||
else if (typeof define == "function" && define.amd) // AMD
|
|||
define(["../../lib/codemirror"], mod); |
|||
else // Plain browser env
|
|||
mod(CodeMirror); |
|||
})(function(CodeMirror) { |
|||
"use strict"; |
|||
|
|||
// Depends on js-yaml.js from https://github.com/nodeca/js-yaml
|
|||
|
|||
// declare global: jsyaml
|
|||
|
|||
CodeMirror.registerHelper("lint", "yaml", function(text) { |
|||
var found = []; |
|||
if (!window.jsyaml) { |
|||
if (window.console) { |
|||
window.console.error("Error: window.jsyaml not defined, CodeMirror YAML linting cannot run."); |
|||
} |
|||
return found; |
|||
} |
|||
try { jsyaml.loadAll(text); } |
|||
catch(e) { |
|||
var loc = e.mark, |
|||
// js-yaml YAMLException doesn't always provide an accurate lineno
|
|||
// e.g., when there are multiple yaml docs
|
|||
// ---
|
|||
// ---
|
|||
// foo:bar
|
|||
from = loc ? CodeMirror.Pos(loc.line, loc.column) : CodeMirror.Pos(0, 0), |
|||
to = from; |
|||
found.push({ from: from, to: to, message: e.message }); |
|||
} |
|||
return found; |
|||
}); |
|||
|
|||
}); |
|||
@ -0,0 +1,119 @@ |
|||
.CodeMirror-merge { |
|||
position: relative; |
|||
border: 1px solid #ddd; |
|||
white-space: pre; |
|||
} |
|||
|
|||
.CodeMirror-merge, .CodeMirror-merge .CodeMirror { |
|||
height: 350px; |
|||
} |
|||
|
|||
.CodeMirror-merge-2pane .CodeMirror-merge-pane { width: 47%; } |
|||
.CodeMirror-merge-2pane .CodeMirror-merge-gap { width: 6%; } |
|||
.CodeMirror-merge-3pane .CodeMirror-merge-pane { width: 31%; } |
|||
.CodeMirror-merge-3pane .CodeMirror-merge-gap { width: 3.5%; } |
|||
|
|||
.CodeMirror-merge-pane { |
|||
display: inline-block; |
|||
white-space: normal; |
|||
vertical-align: top; |
|||
} |
|||
.CodeMirror-merge-pane-rightmost { |
|||
position: absolute; |
|||
right: 0px; |
|||
z-index: 1; |
|||
} |
|||
|
|||
.CodeMirror-merge-gap { |
|||
z-index: 2; |
|||
display: inline-block; |
|||
height: 100%; |
|||
-moz-box-sizing: border-box; |
|||
box-sizing: border-box; |
|||
overflow: hidden; |
|||
border-left: 1px solid #ddd; |
|||
border-right: 1px solid #ddd; |
|||
position: relative; |
|||
background: #f8f8f8; |
|||
} |
|||
|
|||
.CodeMirror-merge-scrolllock-wrap { |
|||
position: absolute; |
|||
bottom: 0; left: 50%; |
|||
} |
|||
.CodeMirror-merge-scrolllock { |
|||
position: relative; |
|||
left: -50%; |
|||
cursor: pointer; |
|||
color: #555; |
|||
line-height: 1; |
|||
} |
|||
.CodeMirror-merge-scrolllock:after { |
|||
content: "\21db\00a0\00a0\21da"; |
|||
} |
|||
.CodeMirror-merge-scrolllock.CodeMirror-merge-scrolllock-enabled:after { |
|||
content: "\21db\21da"; |
|||
} |
|||
|
|||
.CodeMirror-merge-copybuttons-left, .CodeMirror-merge-copybuttons-right { |
|||
position: absolute; |
|||
left: 0; top: 0; |
|||
right: 0; bottom: 0; |
|||
line-height: 1; |
|||
} |
|||
|
|||
.CodeMirror-merge-copy { |
|||
position: absolute; |
|||
cursor: pointer; |
|||
color: #44c; |
|||
z-index: 3; |
|||
} |
|||
|
|||
.CodeMirror-merge-copy-reverse { |
|||
position: absolute; |
|||
cursor: pointer; |
|||
color: #44c; |
|||
} |
|||
|
|||
.CodeMirror-merge-copybuttons-left .CodeMirror-merge-copy { left: 2px; } |
|||
.CodeMirror-merge-copybuttons-right .CodeMirror-merge-copy { right: 2px; } |
|||
|
|||
.CodeMirror-merge-r-inserted, .CodeMirror-merge-l-inserted { |
|||
background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAMAAAACCAYAAACddGYaAAAAGUlEQVQI12MwuCXy3+CWyH8GBgYGJgYkAABZbAQ9ELXurwAAAABJRU5ErkJggg==); |
|||
background-position: bottom left; |
|||
background-repeat: repeat-x; |
|||
} |
|||
|
|||
.CodeMirror-merge-r-deleted, .CodeMirror-merge-l-deleted { |
|||
background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAMAAAACCAYAAACddGYaAAAAGUlEQVQI12M4Kyb2/6yY2H8GBgYGJgYkAABURgPz6Ks7wQAAAABJRU5ErkJggg==); |
|||
background-position: bottom left; |
|||
background-repeat: repeat-x; |
|||
} |
|||
|
|||
.CodeMirror-merge-r-chunk { background: #ffffe0; } |
|||
.CodeMirror-merge-r-chunk-start { border-top: 1px solid #ee8; } |
|||
.CodeMirror-merge-r-chunk-end { border-bottom: 1px solid #ee8; } |
|||
.CodeMirror-merge-r-connect { fill: #ffffe0; stroke: #ee8; stroke-width: 1px; } |
|||
|
|||
.CodeMirror-merge-l-chunk { background: #eef; } |
|||
.CodeMirror-merge-l-chunk-start { border-top: 1px solid #88e; } |
|||
.CodeMirror-merge-l-chunk-end { border-bottom: 1px solid #88e; } |
|||
.CodeMirror-merge-l-connect { fill: #eef; stroke: #88e; stroke-width: 1px; } |
|||
|
|||
.CodeMirror-merge-l-chunk.CodeMirror-merge-r-chunk { background: #dfd; } |
|||
.CodeMirror-merge-l-chunk-start.CodeMirror-merge-r-chunk-start { border-top: 1px solid #4e4; } |
|||
.CodeMirror-merge-l-chunk-end.CodeMirror-merge-r-chunk-end { border-bottom: 1px solid #4e4; } |
|||
|
|||
.CodeMirror-merge-collapsed-widget:before { |
|||
content: "(...)"; |
|||
} |
|||
.CodeMirror-merge-collapsed-widget { |
|||
cursor: pointer; |
|||
color: #88b; |
|||
background: #eef; |
|||
border: 1px solid #ddf; |
|||
font-size: 90%; |
|||
padding: 0 3px; |
|||
border-radius: 4px; |
|||
} |
|||
.CodeMirror-merge-collapsed-line .CodeMirror-gutter-elt { display: none; } |
|||
File diff suppressed because it is too large
@ -0,0 +1,66 @@ |
|||
// CodeMirror, copyright (c) by Marijn Haverbeke and others
|
|||
// Distributed under an MIT license: https://codemirror.net/LICENSE
|
|||
|
|||
(function(mod) { |
|||
if (typeof exports == "object" && typeof module == "object") // CommonJS
|
|||
mod(require("../../lib/codemirror"), "cjs"); |
|||
else if (typeof define == "function" && define.amd) // AMD
|
|||
define(["../../lib/codemirror"], function(CM) { mod(CM, "amd"); }); |
|||
else // Plain browser env
|
|||
mod(CodeMirror, "plain"); |
|||
})(function(CodeMirror, env) { |
|||
if (!CodeMirror.modeURL) CodeMirror.modeURL = "../mode/%N/%N.js"; |
|||
|
|||
var loading = {}; |
|||
function splitCallback(cont, n) { |
|||
var countDown = n; |
|||
return function() { if (--countDown == 0) cont(); }; |
|||
} |
|||
function ensureDeps(mode, cont, options) { |
|||
var modeObj = CodeMirror.modes[mode], deps = modeObj && modeObj.dependencies; |
|||
if (!deps) return cont(); |
|||
var missing = []; |
|||
for (var i = 0; i < deps.length; ++i) { |
|||
if (!CodeMirror.modes.hasOwnProperty(deps[i])) |
|||
missing.push(deps[i]); |
|||
} |
|||
if (!missing.length) return cont(); |
|||
var split = splitCallback(cont, missing.length); |
|||
for (var i = 0; i < missing.length; ++i) |
|||
CodeMirror.requireMode(missing[i], split, options); |
|||
} |
|||
|
|||
CodeMirror.requireMode = function(mode, cont, options) { |
|||
if (typeof mode != "string") mode = mode.name; |
|||
if (CodeMirror.modes.hasOwnProperty(mode)) return ensureDeps(mode, cont, options); |
|||
if (loading.hasOwnProperty(mode)) return loading[mode].push(cont); |
|||
|
|||
var file = options && options.path ? options.path(mode) : CodeMirror.modeURL.replace(/%N/g, mode); |
|||
if (options && options.loadMode) { |
|||
options.loadMode(file, function() { ensureDeps(mode, cont, options) }) |
|||
} else if (env == "plain") { |
|||
var script = document.createElement("script"); |
|||
script.src = file; |
|||
var others = document.getElementsByTagName("script")[0]; |
|||
var list = loading[mode] = [cont]; |
|||
CodeMirror.on(script, "load", function() { |
|||
ensureDeps(mode, function() { |
|||
for (var i = 0; i < list.length; ++i) list[i](); |
|||
}, options); |
|||
}); |
|||
others.parentNode.insertBefore(script, others); |
|||
} else if (env == "cjs") { |
|||
require(file); |
|||
cont(); |
|||
} else if (env == "amd") { |
|||
requirejs([file], cont); |
|||
} |
|||
}; |
|||
|
|||
CodeMirror.autoLoadMode = function(instance, mode, options) { |
|||
if (!CodeMirror.modes.hasOwnProperty(mode)) |
|||
CodeMirror.requireMode(mode, function() { |
|||
instance.setOption("mode", instance.getOption("mode")); |
|||
}, options); |
|||
}; |
|||
}); |
|||
@ -0,0 +1,136 @@ |
|||
// CodeMirror, copyright (c) by Marijn Haverbeke and others
|
|||
// Distributed under an MIT license: https://codemirror.net/LICENSE
|
|||
|
|||
(function(mod) { |
|||
if (typeof exports == "object" && typeof module == "object") // CommonJS
|
|||
mod(require("../../lib/codemirror")); |
|||
else if (typeof define == "function" && define.amd) // AMD
|
|||
define(["../../lib/codemirror"], mod); |
|||
else // Plain browser env
|
|||
mod(CodeMirror); |
|||
})(function(CodeMirror) { |
|||
"use strict"; |
|||
|
|||
CodeMirror.multiplexingMode = function(outer /*, others */) { |
|||
// Others should be {open, close, mode [, delimStyle] [, innerStyle] [, parseDelimiters]} objects
|
|||
var others = Array.prototype.slice.call(arguments, 1); |
|||
|
|||
function indexOf(string, pattern, from, returnEnd) { |
|||
if (typeof pattern == "string") { |
|||
var found = string.indexOf(pattern, from); |
|||
return returnEnd && found > -1 ? found + pattern.length : found; |
|||
} |
|||
var m = pattern.exec(from ? string.slice(from) : string); |
|||
return m ? m.index + from + (returnEnd ? m[0].length : 0) : -1; |
|||
} |
|||
|
|||
return { |
|||
startState: function() { |
|||
return { |
|||
outer: CodeMirror.startState(outer), |
|||
innerActive: null, |
|||
inner: null, |
|||
startingInner: false |
|||
}; |
|||
}, |
|||
|
|||
copyState: function(state) { |
|||
return { |
|||
outer: CodeMirror.copyState(outer, state.outer), |
|||
innerActive: state.innerActive, |
|||
inner: state.innerActive && CodeMirror.copyState(state.innerActive.mode, state.inner), |
|||
startingInner: state.startingInner |
|||
}; |
|||
}, |
|||
|
|||
token: function(stream, state) { |
|||
if (!state.innerActive) { |
|||
var cutOff = Infinity, oldContent = stream.string; |
|||
for (var i = 0; i < others.length; ++i) { |
|||
var other = others[i]; |
|||
var found = indexOf(oldContent, other.open, stream.pos); |
|||
if (found == stream.pos) { |
|||
if (!other.parseDelimiters) stream.match(other.open); |
|||
state.startingInner = !!other.parseDelimiters |
|||
state.innerActive = other; |
|||
|
|||
// Get the outer indent, making sure to handle CodeMirror.Pass
|
|||
var outerIndent = 0; |
|||
if (outer.indent) { |
|||
var possibleOuterIndent = outer.indent(state.outer, "", ""); |
|||
if (possibleOuterIndent !== CodeMirror.Pass) outerIndent = possibleOuterIndent; |
|||
} |
|||
|
|||
state.inner = CodeMirror.startState(other.mode, outerIndent); |
|||
return other.delimStyle && (other.delimStyle + " " + other.delimStyle + "-open"); |
|||
} else if (found != -1 && found < cutOff) { |
|||
cutOff = found; |
|||
} |
|||
} |
|||
if (cutOff != Infinity) stream.string = oldContent.slice(0, cutOff); |
|||
var outerToken = outer.token(stream, state.outer); |
|||
if (cutOff != Infinity) stream.string = oldContent; |
|||
return outerToken; |
|||
} else { |
|||
var curInner = state.innerActive, oldContent = stream.string; |
|||
if (!curInner.close && stream.sol()) { |
|||
state.innerActive = state.inner = null; |
|||
return this.token(stream, state); |
|||
} |
|||
var found = curInner.close && !state.startingInner ? |
|||
indexOf(oldContent, curInner.close, stream.pos, curInner.parseDelimiters) : -1; |
|||
if (found == stream.pos && !curInner.parseDelimiters) { |
|||
stream.match(curInner.close); |
|||
state.innerActive = state.inner = null; |
|||
return curInner.delimStyle && (curInner.delimStyle + " " + curInner.delimStyle + "-close"); |
|||
} |
|||
if (found > -1) stream.string = oldContent.slice(0, found); |
|||
var innerToken = curInner.mode.token(stream, state.inner); |
|||
if (found > -1) stream.string = oldContent; |
|||
else if (stream.pos > stream.start) state.startingInner = false |
|||
|
|||
if (found == stream.pos && curInner.parseDelimiters) |
|||
state.innerActive = state.inner = null; |
|||
|
|||
if (curInner.innerStyle) { |
|||
if (innerToken) innerToken = innerToken + " " + curInner.innerStyle; |
|||
else innerToken = curInner.innerStyle; |
|||
} |
|||
|
|||
return innerToken; |
|||
} |
|||
}, |
|||
|
|||
indent: function(state, textAfter, line) { |
|||
var mode = state.innerActive ? state.innerActive.mode : outer; |
|||
if (!mode.indent) return CodeMirror.Pass; |
|||
return mode.indent(state.innerActive ? state.inner : state.outer, textAfter, line); |
|||
}, |
|||
|
|||
blankLine: function(state) { |
|||
var mode = state.innerActive ? state.innerActive.mode : outer; |
|||
if (mode.blankLine) { |
|||
mode.blankLine(state.innerActive ? state.inner : state.outer); |
|||
} |
|||
if (!state.innerActive) { |
|||
for (var i = 0; i < others.length; ++i) { |
|||
var other = others[i]; |
|||
if (other.open === "\n") { |
|||
state.innerActive = other; |
|||
state.inner = CodeMirror.startState(other.mode, mode.indent ? mode.indent(state.outer, "", "") : 0); |
|||
} |
|||
} |
|||
} else if (state.innerActive.close === "\n") { |
|||
state.innerActive = state.inner = null; |
|||
} |
|||
}, |
|||
|
|||
electricChars: outer.electricChars, |
|||
|
|||
innerMode: function(state) { |
|||
return state.inner ? {state: state.inner, mode: state.innerActive.mode} : {state: state.outer, mode: outer}; |
|||
} |
|||
}; |
|||
}; |
|||
|
|||
}); |
|||
@ -0,0 +1,49 @@ |
|||
// CodeMirror, copyright (c) by Marijn Haverbeke and others
|
|||
// Distributed under an MIT license: https://codemirror.net/LICENSE
|
|||
|
|||
(function() { |
|||
CodeMirror.defineMode("markdown_with_stex", function(){ |
|||
var inner = CodeMirror.getMode({}, "stex"); |
|||
var outer = CodeMirror.getMode({}, "markdown"); |
|||
|
|||
var innerOptions = { |
|||
open: '$', |
|||
close: '$', |
|||
mode: inner, |
|||
delimStyle: 'delim', |
|||
innerStyle: 'inner' |
|||
}; |
|||
|
|||
return CodeMirror.multiplexingMode(outer, innerOptions); |
|||
}); |
|||
|
|||
var mode = CodeMirror.getMode({}, "markdown_with_stex"); |
|||
|
|||
function MT(name) { |
|||
test.mode( |
|||
name, |
|||
mode, |
|||
Array.prototype.slice.call(arguments, 1), |
|||
'multiplexing'); |
|||
} |
|||
|
|||
MT( |
|||
"stexInsideMarkdown", |
|||
"[strong **Equation:**] [delim&delim-open $][inner&tag \\pi][delim&delim-close $]"); |
|||
|
|||
CodeMirror.defineMode("identical_delim_multiplex", function() { |
|||
return CodeMirror.multiplexingMode(CodeMirror.getMode({indentUnit: 2}, "javascript"), { |
|||
open: "#", |
|||
close: "#", |
|||
mode: CodeMirror.getMode({}, "markdown"), |
|||
parseDelimiters: true, |
|||
innerStyle: "q" |
|||
}); |
|||
}); |
|||
|
|||
var mode2 = CodeMirror.getMode({}, "identical_delim_multiplex"); |
|||
|
|||
test.mode("identical_delimiters_with_parseDelimiters", mode2, [ |
|||
"[keyword let] [def x] [operator =] [q #foo][q&em *bar*][q #];" |
|||
], "multiplexing") |
|||
})(); |
|||
@ -0,0 +1,90 @@ |
|||
// CodeMirror, copyright (c) by Marijn Haverbeke and others
|
|||
// Distributed under an MIT license: https://codemirror.net/LICENSE
|
|||
|
|||
// Utility function that allows modes to be combined. The mode given
|
|||
// as the base argument takes care of most of the normal mode
|
|||
// functionality, but a second (typically simple) mode is used, which
|
|||
// can override the style of text. Both modes get to parse all of the
|
|||
// text, but when both assign a non-null style to a piece of code, the
|
|||
// overlay wins, unless the combine argument was true and not overridden,
|
|||
// or state.overlay.combineTokens was true, in which case the styles are
|
|||
// combined.
|
|||
|
|||
(function(mod) { |
|||
if (typeof exports == "object" && typeof module == "object") // CommonJS
|
|||
mod(require("../../lib/codemirror")); |
|||
else if (typeof define == "function" && define.amd) // AMD
|
|||
define(["../../lib/codemirror"], mod); |
|||
else // Plain browser env
|
|||
mod(CodeMirror); |
|||
})(function(CodeMirror) { |
|||
"use strict"; |
|||
|
|||
CodeMirror.overlayMode = function(base, overlay, combine) { |
|||
return { |
|||
startState: function() { |
|||
return { |
|||
base: CodeMirror.startState(base), |
|||
overlay: CodeMirror.startState(overlay), |
|||
basePos: 0, baseCur: null, |
|||
overlayPos: 0, overlayCur: null, |
|||
streamSeen: null |
|||
}; |
|||
}, |
|||
copyState: function(state) { |
|||
return { |
|||
base: CodeMirror.copyState(base, state.base), |
|||
overlay: CodeMirror.copyState(overlay, state.overlay), |
|||
basePos: state.basePos, baseCur: null, |
|||
overlayPos: state.overlayPos, overlayCur: null |
|||
}; |
|||
}, |
|||
|
|||
token: function(stream, state) { |
|||
if (stream != state.streamSeen || |
|||
Math.min(state.basePos, state.overlayPos) < stream.start) { |
|||
state.streamSeen = stream; |
|||
state.basePos = state.overlayPos = stream.start; |
|||
} |
|||
|
|||
if (stream.start == state.basePos) { |
|||
state.baseCur = base.token(stream, state.base); |
|||
state.basePos = stream.pos; |
|||
} |
|||
if (stream.start == state.overlayPos) { |
|||
stream.pos = stream.start; |
|||
state.overlayCur = overlay.token(stream, state.overlay); |
|||
state.overlayPos = stream.pos; |
|||
} |
|||
stream.pos = Math.min(state.basePos, state.overlayPos); |
|||
|
|||
// state.overlay.combineTokens always takes precedence over combine,
|
|||
// unless set to null
|
|||
if (state.overlayCur == null) return state.baseCur; |
|||
else if (state.baseCur != null && |
|||
state.overlay.combineTokens || |
|||
combine && state.overlay.combineTokens == null) |
|||
return state.baseCur + " " + state.overlayCur; |
|||
else return state.overlayCur; |
|||
}, |
|||
|
|||
indent: base.indent && function(state, textAfter, line) { |
|||
return base.indent(state.base, textAfter, line); |
|||
}, |
|||
electricChars: base.electricChars, |
|||
|
|||
innerMode: function(state) { return {state: state.base, mode: base}; }, |
|||
|
|||
blankLine: function(state) { |
|||
var baseToken, overlayToken; |
|||
if (base.blankLine) baseToken = base.blankLine(state.base); |
|||
if (overlay.blankLine) overlayToken = overlay.blankLine(state.overlay); |
|||
|
|||
return overlayToken == null ? |
|||
baseToken : |
|||
(combine && baseToken != null ? baseToken + " " + overlayToken : overlayToken); |
|||
} |
|||
}; |
|||
}; |
|||
|
|||
}); |
|||
@ -0,0 +1,216 @@ |
|||
// CodeMirror, copyright (c) by Marijn Haverbeke and others
|
|||
// Distributed under an MIT license: https://codemirror.net/LICENSE
|
|||
|
|||
(function(mod) { |
|||
if (typeof exports == "object" && typeof module == "object") // CommonJS
|
|||
mod(require("../../lib/codemirror")); |
|||
else if (typeof define == "function" && define.amd) // AMD
|
|||
define(["../../lib/codemirror"], mod); |
|||
else // Plain browser env
|
|||
mod(CodeMirror); |
|||
})(function(CodeMirror) { |
|||
"use strict"; |
|||
|
|||
CodeMirror.defineSimpleMode = function(name, states) { |
|||
CodeMirror.defineMode(name, function(config) { |
|||
return CodeMirror.simpleMode(config, states); |
|||
}); |
|||
}; |
|||
|
|||
CodeMirror.simpleMode = function(config, states) { |
|||
ensureState(states, "start"); |
|||
var states_ = {}, meta = states.meta || {}, hasIndentation = false; |
|||
for (var state in states) if (state != meta && states.hasOwnProperty(state)) { |
|||
var list = states_[state] = [], orig = states[state]; |
|||
for (var i = 0; i < orig.length; i++) { |
|||
var data = orig[i]; |
|||
list.push(new Rule(data, states)); |
|||
if (data.indent || data.dedent) hasIndentation = true; |
|||
} |
|||
} |
|||
var mode = { |
|||
startState: function() { |
|||
return {state: "start", pending: null, |
|||
local: null, localState: null, |
|||
indent: hasIndentation ? [] : null}; |
|||
}, |
|||
copyState: function(state) { |
|||
var s = {state: state.state, pending: state.pending, |
|||
local: state.local, localState: null, |
|||
indent: state.indent && state.indent.slice(0)}; |
|||
if (state.localState) |
|||
s.localState = CodeMirror.copyState(state.local.mode, state.localState); |
|||
if (state.stack) |
|||
s.stack = state.stack.slice(0); |
|||
for (var pers = state.persistentStates; pers; pers = pers.next) |
|||
s.persistentStates = {mode: pers.mode, |
|||
spec: pers.spec, |
|||
state: pers.state == state.localState ? s.localState : CodeMirror.copyState(pers.mode, pers.state), |
|||
next: s.persistentStates}; |
|||
return s; |
|||
}, |
|||
token: tokenFunction(states_, config), |
|||
innerMode: function(state) { return state.local && {mode: state.local.mode, state: state.localState}; }, |
|||
indent: indentFunction(states_, meta) |
|||
}; |
|||
if (meta) for (var prop in meta) if (meta.hasOwnProperty(prop)) |
|||
mode[prop] = meta[prop]; |
|||
return mode; |
|||
}; |
|||
|
|||
function ensureState(states, name) { |
|||
if (!states.hasOwnProperty(name)) |
|||
throw new Error("Undefined state " + name + " in simple mode"); |
|||
} |
|||
|
|||
function toRegex(val, caret) { |
|||
if (!val) return /(?:)/; |
|||
var flags = ""; |
|||
if (val instanceof RegExp) { |
|||
if (val.ignoreCase) flags = "i"; |
|||
if (val.unicode) flags += "u" |
|||
val = val.source; |
|||
} else { |
|||
val = String(val); |
|||
} |
|||
return new RegExp((caret === false ? "" : "^") + "(?:" + val + ")", flags); |
|||
} |
|||
|
|||
function asToken(val) { |
|||
if (!val) return null; |
|||
if (val.apply) return val |
|||
if (typeof val == "string") return val.replace(/\./g, " "); |
|||
var result = []; |
|||
for (var i = 0; i < val.length; i++) |
|||
result.push(val[i] && val[i].replace(/\./g, " ")); |
|||
return result; |
|||
} |
|||
|
|||
function Rule(data, states) { |
|||
if (data.next || data.push) ensureState(states, data.next || data.push); |
|||
this.regex = toRegex(data.regex); |
|||
this.token = asToken(data.token); |
|||
this.data = data; |
|||
} |
|||
|
|||
function tokenFunction(states, config) { |
|||
return function(stream, state) { |
|||
if (state.pending) { |
|||
var pend = state.pending.shift(); |
|||
if (state.pending.length == 0) state.pending = null; |
|||
stream.pos += pend.text.length; |
|||
return pend.token; |
|||
} |
|||
|
|||
if (state.local) { |
|||
if (state.local.end && stream.match(state.local.end)) { |
|||
var tok = state.local.endToken || null; |
|||
state.local = state.localState = null; |
|||
return tok; |
|||
} else { |
|||
var tok = state.local.mode.token(stream, state.localState), m; |
|||
if (state.local.endScan && (m = state.local.endScan.exec(stream.current()))) |
|||
stream.pos = stream.start + m.index; |
|||
return tok; |
|||
} |
|||
} |
|||
|
|||
var curState = states[state.state]; |
|||
for (var i = 0; i < curState.length; i++) { |
|||
var rule = curState[i]; |
|||
var matches = (!rule.data.sol || stream.sol()) && stream.match(rule.regex); |
|||
if (matches) { |
|||
if (rule.data.next) { |
|||
state.state = rule.data.next; |
|||
} else if (rule.data.push) { |
|||
(state.stack || (state.stack = [])).push(state.state); |
|||
state.state = rule.data.push; |
|||
} else if (rule.data.pop && state.stack && state.stack.length) { |
|||
state.state = state.stack.pop(); |
|||
} |
|||
|
|||
if (rule.data.mode) |
|||
enterLocalMode(config, state, rule.data.mode, rule.token); |
|||
if (rule.data.indent) |
|||
state.indent.push(stream.indentation() + config.indentUnit); |
|||
if (rule.data.dedent) |
|||
state.indent.pop(); |
|||
var token = rule.token |
|||
if (token && token.apply) token = token(matches) |
|||
if (matches.length > 2 && rule.token && typeof rule.token != "string") { |
|||
for (var j = 2; j < matches.length; j++) |
|||
if (matches[j]) |
|||
(state.pending || (state.pending = [])).push({text: matches[j], token: rule.token[j - 1]}); |
|||
stream.backUp(matches[0].length - (matches[1] ? matches[1].length : 0)); |
|||
return token[0]; |
|||
} else if (token && token.join) { |
|||
return token[0]; |
|||
} else { |
|||
return token; |
|||
} |
|||
} |
|||
} |
|||
stream.next(); |
|||
return null; |
|||
}; |
|||
} |
|||
|
|||
function cmp(a, b) { |
|||
if (a === b) return true; |
|||
if (!a || typeof a != "object" || !b || typeof b != "object") return false; |
|||
var props = 0; |
|||
for (var prop in a) if (a.hasOwnProperty(prop)) { |
|||
if (!b.hasOwnProperty(prop) || !cmp(a[prop], b[prop])) return false; |
|||
props++; |
|||
} |
|||
for (var prop in b) if (b.hasOwnProperty(prop)) props--; |
|||
return props == 0; |
|||
} |
|||
|
|||
function enterLocalMode(config, state, spec, token) { |
|||
var pers; |
|||
if (spec.persistent) for (var p = state.persistentStates; p && !pers; p = p.next) |
|||
if (spec.spec ? cmp(spec.spec, p.spec) : spec.mode == p.mode) pers = p; |
|||
var mode = pers ? pers.mode : spec.mode || CodeMirror.getMode(config, spec.spec); |
|||
var lState = pers ? pers.state : CodeMirror.startState(mode); |
|||
if (spec.persistent && !pers) |
|||
state.persistentStates = {mode: mode, spec: spec.spec, state: lState, next: state.persistentStates}; |
|||
|
|||
state.localState = lState; |
|||
state.local = {mode: mode, |
|||
end: spec.end && toRegex(spec.end), |
|||
endScan: spec.end && spec.forceEnd !== false && toRegex(spec.end, false), |
|||
endToken: token && token.join ? token[token.length - 1] : token}; |
|||
} |
|||
|
|||
function indexOf(val, arr) { |
|||
for (var i = 0; i < arr.length; i++) if (arr[i] === val) return true; |
|||
} |
|||
|
|||
function indentFunction(states, meta) { |
|||
return function(state, textAfter, line) { |
|||
if (state.local && state.local.mode.indent) |
|||
return state.local.mode.indent(state.localState, textAfter, line); |
|||
if (state.indent == null || state.local || meta.dontIndentStates && indexOf(state.state, meta.dontIndentStates) > -1) |
|||
return CodeMirror.Pass; |
|||
|
|||
var pos = state.indent.length - 1, rules = states[state.state]; |
|||
scan: for (;;) { |
|||
for (var i = 0; i < rules.length; i++) { |
|||
var rule = rules[i]; |
|||
if (rule.data.dedent && rule.data.dedentIfLineStart !== false) { |
|||
var m = rule.regex.exec(textAfter); |
|||
if (m && m[0]) { |
|||
pos--; |
|||
if (rule.next || rule.push) rules = states[rule.next || rule.push]; |
|||
textAfter = textAfter.slice(m[0].length); |
|||
continue scan; |
|||
} |
|||
} |
|||
} |
|||
break; |
|||
} |
|||
return pos < 0 ? 0 : state.indent[pos]; |
|||
}; |
|||
} |
|||
}); |
|||
@ -0,0 +1,40 @@ |
|||
// CodeMirror, copyright (c) by Marijn Haverbeke and others
|
|||
// Distributed under an MIT license: https://codemirror.net/LICENSE
|
|||
|
|||
(function(mod) { |
|||
if (typeof exports == "object" && typeof module == "object") // CommonJS
|
|||
mod(require("../../lib/codemirror"), require("./runmode")); |
|||
else if (typeof define == "function" && define.amd) // AMD
|
|||
define(["../../lib/codemirror", "./runmode"], mod); |
|||
else // Plain browser env
|
|||
mod(CodeMirror); |
|||
})(function(CodeMirror) { |
|||
"use strict"; |
|||
|
|||
var isBlock = /^(p|li|div|h\\d|pre|blockquote|td)$/; |
|||
|
|||
function textContent(node, out) { |
|||
if (node.nodeType == 3) return out.push(node.nodeValue); |
|||
for (var ch = node.firstChild; ch; ch = ch.nextSibling) { |
|||
textContent(ch, out); |
|||
if (isBlock.test(node.nodeType)) out.push("\n"); |
|||
} |
|||
} |
|||
|
|||
CodeMirror.colorize = function(collection, defaultMode) { |
|||
if (!collection) collection = document.body.getElementsByTagName("pre"); |
|||
|
|||
for (var i = 0; i < collection.length; ++i) { |
|||
var node = collection[i]; |
|||
var mode = node.getAttribute("data-lang") || defaultMode; |
|||
if (!mode) continue; |
|||
|
|||
var text = []; |
|||
textContent(node, text); |
|||
node.innerHTML = ""; |
|||
CodeMirror.runMode(text.join(""), mode, node); |
|||
|
|||
node.className += " cm-s-default"; |
|||
} |
|||
}; |
|||
}); |
|||
@ -0,0 +1,334 @@ |
|||
(function () { |
|||
'use strict'; |
|||
|
|||
function copyObj(obj, target, overwrite) { |
|||
if (!target) { target = {}; } |
|||
for (var prop in obj) |
|||
{ if (obj.hasOwnProperty(prop) && (overwrite !== false || !target.hasOwnProperty(prop))) |
|||
{ target[prop] = obj[prop]; } } |
|||
return target |
|||
} |
|||
|
|||
// Counts the column offset in a string, taking tabs into account.
|
|||
// Used mostly to find indentation.
|
|||
function countColumn(string, end, tabSize, startIndex, startValue) { |
|||
if (end == null) { |
|||
end = string.search(/[^\s\u00a0]/); |
|||
if (end == -1) { end = string.length; } |
|||
} |
|||
for (var i = startIndex || 0, n = startValue || 0;;) { |
|||
var nextTab = string.indexOf("\t", i); |
|||
if (nextTab < 0 || nextTab >= end) |
|||
{ return n + (end - i) } |
|||
n += nextTab - i; |
|||
n += tabSize - (n % tabSize); |
|||
i = nextTab + 1; |
|||
} |
|||
} |
|||
|
|||
function nothing() {} |
|||
|
|||
function createObj(base, props) { |
|||
var inst; |
|||
if (Object.create) { |
|||
inst = Object.create(base); |
|||
} else { |
|||
nothing.prototype = base; |
|||
inst = new nothing(); |
|||
} |
|||
if (props) { copyObj(props, inst); } |
|||
return inst |
|||
} |
|||
|
|||
// STRING STREAM
|
|||
|
|||
// Fed to the mode parsers, provides helper functions to make
|
|||
// parsers more succinct.
|
|||
|
|||
var StringStream = function(string, tabSize, lineOracle) { |
|||
this.pos = this.start = 0; |
|||
this.string = string; |
|||
this.tabSize = tabSize || 8; |
|||
this.lastColumnPos = this.lastColumnValue = 0; |
|||
this.lineStart = 0; |
|||
this.lineOracle = lineOracle; |
|||
}; |
|||
|
|||
StringStream.prototype.eol = function () {return this.pos >= this.string.length}; |
|||
StringStream.prototype.sol = function () {return this.pos == this.lineStart}; |
|||
StringStream.prototype.peek = function () {return this.string.charAt(this.pos) || undefined}; |
|||
StringStream.prototype.next = function () { |
|||
if (this.pos < this.string.length) |
|||
{ return this.string.charAt(this.pos++) } |
|||
}; |
|||
StringStream.prototype.eat = function (match) { |
|||
var ch = this.string.charAt(this.pos); |
|||
var ok; |
|||
if (typeof match == "string") { ok = ch == match; } |
|||
else { ok = ch && (match.test ? match.test(ch) : match(ch)); } |
|||
if (ok) {++this.pos; return ch} |
|||
}; |
|||
StringStream.prototype.eatWhile = function (match) { |
|||
var start = this.pos; |
|||
while (this.eat(match)){} |
|||
return this.pos > start |
|||
}; |
|||
StringStream.prototype.eatSpace = function () { |
|||
var start = this.pos; |
|||
while (/[\s\u00a0]/.test(this.string.charAt(this.pos))) { ++this.pos; } |
|||
return this.pos > start |
|||
}; |
|||
StringStream.prototype.skipToEnd = function () {this.pos = this.string.length;}; |
|||
StringStream.prototype.skipTo = function (ch) { |
|||
var found = this.string.indexOf(ch, this.pos); |
|||
if (found > -1) {this.pos = found; return true} |
|||
}; |
|||
StringStream.prototype.backUp = function (n) {this.pos -= n;}; |
|||
StringStream.prototype.column = function () { |
|||
if (this.lastColumnPos < this.start) { |
|||
this.lastColumnValue = countColumn(this.string, this.start, this.tabSize, this.lastColumnPos, this.lastColumnValue); |
|||
this.lastColumnPos = this.start; |
|||
} |
|||
return this.lastColumnValue - (this.lineStart ? countColumn(this.string, this.lineStart, this.tabSize) : 0) |
|||
}; |
|||
StringStream.prototype.indentation = function () { |
|||
return countColumn(this.string, null, this.tabSize) - |
|||
(this.lineStart ? countColumn(this.string, this.lineStart, this.tabSize) : 0) |
|||
}; |
|||
StringStream.prototype.match = function (pattern, consume, caseInsensitive) { |
|||
if (typeof pattern == "string") { |
|||
var cased = function (str) { return caseInsensitive ? str.toLowerCase() : str; }; |
|||
var substr = this.string.substr(this.pos, pattern.length); |
|||
if (cased(substr) == cased(pattern)) { |
|||
if (consume !== false) { this.pos += pattern.length; } |
|||
return true |
|||
} |
|||
} else { |
|||
var match = this.string.slice(this.pos).match(pattern); |
|||
if (match && match.index > 0) { return null } |
|||
if (match && consume !== false) { this.pos += match[0].length; } |
|||
return match |
|||
} |
|||
}; |
|||
StringStream.prototype.current = function (){return this.string.slice(this.start, this.pos)}; |
|||
StringStream.prototype.hideFirstChars = function (n, inner) { |
|||
this.lineStart += n; |
|||
try { return inner() } |
|||
finally { this.lineStart -= n; } |
|||
}; |
|||
StringStream.prototype.lookAhead = function (n) { |
|||
var oracle = this.lineOracle; |
|||
return oracle && oracle.lookAhead(n) |
|||
}; |
|||
StringStream.prototype.baseToken = function () { |
|||
var oracle = this.lineOracle; |
|||
return oracle && oracle.baseToken(this.pos) |
|||
}; |
|||
|
|||
// Known modes, by name and by MIME
|
|||
var modes = {}, mimeModes = {}; |
|||
|
|||
// Extra arguments are stored as the mode's dependencies, which is
|
|||
// used by (legacy) mechanisms like loadmode.js to automatically
|
|||
// load a mode. (Preferred mechanism is the require/define calls.)
|
|||
function defineMode(name, mode) { |
|||
if (arguments.length > 2) |
|||
{ mode.dependencies = Array.prototype.slice.call(arguments, 2); } |
|||
modes[name] = mode; |
|||
} |
|||
|
|||
function defineMIME(mime, spec) { |
|||
mimeModes[mime] = spec; |
|||
} |
|||
|
|||
// Given a MIME type, a {name, ...options} config object, or a name
|
|||
// string, return a mode config object.
|
|||
function resolveMode(spec) { |
|||
if (typeof spec == "string" && mimeModes.hasOwnProperty(spec)) { |
|||
spec = mimeModes[spec]; |
|||
} else if (spec && typeof spec.name == "string" && mimeModes.hasOwnProperty(spec.name)) { |
|||
var found = mimeModes[spec.name]; |
|||
if (typeof found == "string") { found = {name: found}; } |
|||
spec = createObj(found, spec); |
|||
spec.name = found.name; |
|||
} else if (typeof spec == "string" && /^[\w\-]+\/[\w\-]+\+xml$/.test(spec)) { |
|||
return resolveMode("application/xml") |
|||
} else if (typeof spec == "string" && /^[\w\-]+\/[\w\-]+\+json$/.test(spec)) { |
|||
return resolveMode("application/json") |
|||
} |
|||
if (typeof spec == "string") { return {name: spec} } |
|||
else { return spec || {name: "null"} } |
|||
} |
|||
|
|||
// Given a mode spec (anything that resolveMode accepts), find and
|
|||
// initialize an actual mode object.
|
|||
function getMode(options, spec) { |
|||
spec = resolveMode(spec); |
|||
var mfactory = modes[spec.name]; |
|||
if (!mfactory) { return getMode(options, "text/plain") } |
|||
var modeObj = mfactory(options, spec); |
|||
if (modeExtensions.hasOwnProperty(spec.name)) { |
|||
var exts = modeExtensions[spec.name]; |
|||
for (var prop in exts) { |
|||
if (!exts.hasOwnProperty(prop)) { continue } |
|||
if (modeObj.hasOwnProperty(prop)) { modeObj["_" + prop] = modeObj[prop]; } |
|||
modeObj[prop] = exts[prop]; |
|||
} |
|||
} |
|||
modeObj.name = spec.name; |
|||
if (spec.helperType) { modeObj.helperType = spec.helperType; } |
|||
if (spec.modeProps) { for (var prop$1 in spec.modeProps) |
|||
{ modeObj[prop$1] = spec.modeProps[prop$1]; } } |
|||
|
|||
return modeObj |
|||
} |
|||
|
|||
// This can be used to attach properties to mode objects from
|
|||
// outside the actual mode definition.
|
|||
var modeExtensions = {}; |
|||
function extendMode(mode, properties) { |
|||
var exts = modeExtensions.hasOwnProperty(mode) ? modeExtensions[mode] : (modeExtensions[mode] = {}); |
|||
copyObj(properties, exts); |
|||
} |
|||
|
|||
function copyState(mode, state) { |
|||
if (state === true) { return state } |
|||
if (mode.copyState) { return mode.copyState(state) } |
|||
var nstate = {}; |
|||
for (var n in state) { |
|||
var val = state[n]; |
|||
if (val instanceof Array) { val = val.concat([]); } |
|||
nstate[n] = val; |
|||
} |
|||
return nstate |
|||
} |
|||
|
|||
// Given a mode and a state (for that mode), find the inner mode and
|
|||
// state at the position that the state refers to.
|
|||
function innerMode(mode, state) { |
|||
var info; |
|||
while (mode.innerMode) { |
|||
info = mode.innerMode(state); |
|||
if (!info || info.mode == mode) { break } |
|||
state = info.state; |
|||
mode = info.mode; |
|||
} |
|||
return info || {mode: mode, state: state} |
|||
} |
|||
|
|||
function startState(mode, a1, a2) { |
|||
return mode.startState ? mode.startState(a1, a2) : true |
|||
} |
|||
|
|||
var modeMethods = { |
|||
__proto__: null, |
|||
modes: modes, |
|||
mimeModes: mimeModes, |
|||
defineMode: defineMode, |
|||
defineMIME: defineMIME, |
|||
resolveMode: resolveMode, |
|||
getMode: getMode, |
|||
modeExtensions: modeExtensions, |
|||
extendMode: extendMode, |
|||
copyState: copyState, |
|||
innerMode: innerMode, |
|||
startState: startState |
|||
}; |
|||
|
|||
// declare global: globalThis, CodeMirror
|
|||
|
|||
// Create a minimal CodeMirror needed to use runMode, and assign to root.
|
|||
var root = typeof globalThis !== 'undefined' ? globalThis : window; |
|||
root.CodeMirror = {}; |
|||
|
|||
// Copy StringStream and mode methods into CodeMirror object.
|
|||
CodeMirror.StringStream = StringStream; |
|||
for (var exported in modeMethods) { CodeMirror[exported] = modeMethods[exported]; } |
|||
|
|||
// Minimal default mode.
|
|||
CodeMirror.defineMode("null", function () { return ({token: function (stream) { return stream.skipToEnd(); }}); }); |
|||
CodeMirror.defineMIME("text/plain", "null"); |
|||
|
|||
CodeMirror.registerHelper = CodeMirror.registerGlobalHelper = Math.min; |
|||
CodeMirror.splitLines = function(string) { return string.split(/\r?\n|\r/) }; |
|||
CodeMirror.countColumn = countColumn; |
|||
|
|||
CodeMirror.defaults = { indentUnit: 2 }; |
|||
|
|||
// CodeMirror, copyright (c) by Marijn Haverbeke and others
|
|||
// Distributed under an MIT license: https://codemirror.net/LICENSE
|
|||
|
|||
(function(mod) { |
|||
if (typeof exports == "object" && typeof module == "object") // CommonJS
|
|||
{ mod(require("../../lib/codemirror")); } |
|||
else if (typeof define == "function" && define.amd) // AMD
|
|||
{ define(["../../lib/codemirror"], mod); } |
|||
else // Plain browser env
|
|||
{ mod(CodeMirror); } |
|||
})(function(CodeMirror) { |
|||
|
|||
CodeMirror.runMode = function(string, modespec, callback, options) { |
|||
var mode = CodeMirror.getMode(CodeMirror.defaults, modespec); |
|||
var tabSize = (options && options.tabSize) || CodeMirror.defaults.tabSize; |
|||
|
|||
// Create a tokenizing callback function if passed-in callback is a DOM element.
|
|||
if (callback.appendChild) { |
|||
var ie = /MSIE \d/.test(navigator.userAgent); |
|||
var ie_lt9 = ie && (document.documentMode == null || document.documentMode < 9); |
|||
var node = callback, col = 0; |
|||
node.innerHTML = ""; |
|||
callback = function(text, style) { |
|||
if (text == "\n") { |
|||
// Emitting LF or CRLF on IE8 or earlier results in an incorrect display.
|
|||
// Emitting a carriage return makes everything ok.
|
|||
node.appendChild(document.createTextNode(ie_lt9 ? '\r' : text)); |
|||
col = 0; |
|||
return; |
|||
} |
|||
var content = ""; |
|||
// replace tabs
|
|||
for (var pos = 0;;) { |
|||
var idx = text.indexOf("\t", pos); |
|||
if (idx == -1) { |
|||
content += text.slice(pos); |
|||
col += text.length - pos; |
|||
break; |
|||
} else { |
|||
col += idx - pos; |
|||
content += text.slice(pos, idx); |
|||
var size = tabSize - col % tabSize; |
|||
col += size; |
|||
for (var i = 0; i < size; ++i) { content += " "; } |
|||
pos = idx + 1; |
|||
} |
|||
} |
|||
// Create a node with token style and append it to the callback DOM element.
|
|||
if (style) { |
|||
var sp = node.appendChild(document.createElement("span")); |
|||
sp.className = "cm-" + style.replace(/ +/g, " cm-"); |
|||
sp.appendChild(document.createTextNode(content)); |
|||
} else { |
|||
node.appendChild(document.createTextNode(content)); |
|||
} |
|||
}; |
|||
} |
|||
|
|||
var lines = CodeMirror.splitLines(string), state = (options && options.state) || CodeMirror.startState(mode); |
|||
for (var i = 0, e = lines.length; i < e; ++i) { |
|||
if (i) { callback("\n"); } |
|||
var stream = new CodeMirror.StringStream(lines[i], null, { |
|||
lookAhead: function(n) { return lines[i + n] }, |
|||
baseToken: function() {} |
|||
}); |
|||
if (!stream.string && mode.blankLine) { mode.blankLine(state); } |
|||
while (!stream.eol()) { |
|||
var style = mode.token(stream, state); |
|||
callback(stream.current(), style, i, stream.start, state, mode); |
|||
stream.start = stream.pos; |
|||
} |
|||
} |
|||
}; |
|||
|
|||
}); |
|||
|
|||
}()); |
|||
@ -0,0 +1,76 @@ |
|||
// CodeMirror, copyright (c) by Marijn Haverbeke and others
|
|||
// Distributed under an MIT license: https://codemirror.net/LICENSE
|
|||
|
|||
(function(mod) { |
|||
if (typeof exports == "object" && typeof module == "object") // CommonJS
|
|||
mod(require("../../lib/codemirror")); |
|||
else if (typeof define == "function" && define.amd) // AMD
|
|||
define(["../../lib/codemirror"], mod); |
|||
else // Plain browser env
|
|||
mod(CodeMirror); |
|||
})(function(CodeMirror) { |
|||
"use strict"; |
|||
|
|||
CodeMirror.runMode = function(string, modespec, callback, options) { |
|||
var mode = CodeMirror.getMode(CodeMirror.defaults, modespec); |
|||
var tabSize = (options && options.tabSize) || CodeMirror.defaults.tabSize; |
|||
|
|||
// Create a tokenizing callback function if passed-in callback is a DOM element.
|
|||
if (callback.appendChild) { |
|||
var ie = /MSIE \d/.test(navigator.userAgent); |
|||
var ie_lt9 = ie && (document.documentMode == null || document.documentMode < 9); |
|||
var node = callback, col = 0; |
|||
node.innerHTML = ""; |
|||
callback = function(text, style) { |
|||
if (text == "\n") { |
|||
// Emitting LF or CRLF on IE8 or earlier results in an incorrect display.
|
|||
// Emitting a carriage return makes everything ok.
|
|||
node.appendChild(document.createTextNode(ie_lt9 ? '\r' : text)); |
|||
col = 0; |
|||
return; |
|||
} |
|||
var content = ""; |
|||
// replace tabs
|
|||
for (var pos = 0;;) { |
|||
var idx = text.indexOf("\t", pos); |
|||
if (idx == -1) { |
|||
content += text.slice(pos); |
|||
col += text.length - pos; |
|||
break; |
|||
} else { |
|||
col += idx - pos; |
|||
content += text.slice(pos, idx); |
|||
var size = tabSize - col % tabSize; |
|||
col += size; |
|||
for (var i = 0; i < size; ++i) content += " "; |
|||
pos = idx + 1; |
|||
} |
|||
} |
|||
// Create a node with token style and append it to the callback DOM element.
|
|||
if (style) { |
|||
var sp = node.appendChild(document.createElement("span")); |
|||
sp.className = "cm-" + style.replace(/ +/g, " cm-"); |
|||
sp.appendChild(document.createTextNode(content)); |
|||
} else { |
|||
node.appendChild(document.createTextNode(content)); |
|||
} |
|||
}; |
|||
} |
|||
|
|||
var lines = CodeMirror.splitLines(string), state = (options && options.state) || CodeMirror.startState(mode); |
|||
for (var i = 0, e = lines.length; i < e; ++i) { |
|||
if (i) callback("\n"); |
|||
var stream = new CodeMirror.StringStream(lines[i], null, { |
|||
lookAhead: function(n) { return lines[i + n] }, |
|||
baseToken: function() {} |
|||
}); |
|||
if (!stream.string && mode.blankLine) mode.blankLine(state); |
|||
while (!stream.eol()) { |
|||
var style = mode.token(stream, state); |
|||
callback(stream.current(), style, i, stream.start, state, mode); |
|||
stream.start = stream.pos; |
|||
} |
|||
} |
|||
}; |
|||
|
|||
}); |
|||
@ -0,0 +1,329 @@ |
|||
'use strict'; |
|||
|
|||
function copyObj(obj, target, overwrite) { |
|||
if (!target) { target = {}; } |
|||
for (var prop in obj) |
|||
{ if (obj.hasOwnProperty(prop) && (overwrite !== false || !target.hasOwnProperty(prop))) |
|||
{ target[prop] = obj[prop]; } } |
|||
return target |
|||
} |
|||
|
|||
// Counts the column offset in a string, taking tabs into account.
|
|||
// Used mostly to find indentation.
|
|||
function countColumn(string, end, tabSize, startIndex, startValue) { |
|||
if (end == null) { |
|||
end = string.search(/[^\s\u00a0]/); |
|||
if (end == -1) { end = string.length; } |
|||
} |
|||
for (var i = startIndex || 0, n = startValue || 0;;) { |
|||
var nextTab = string.indexOf("\t", i); |
|||
if (nextTab < 0 || nextTab >= end) |
|||
{ return n + (end - i) } |
|||
n += nextTab - i; |
|||
n += tabSize - (n % tabSize); |
|||
i = nextTab + 1; |
|||
} |
|||
} |
|||
|
|||
function nothing() {} |
|||
|
|||
function createObj(base, props) { |
|||
var inst; |
|||
if (Object.create) { |
|||
inst = Object.create(base); |
|||
} else { |
|||
nothing.prototype = base; |
|||
inst = new nothing(); |
|||
} |
|||
if (props) { copyObj(props, inst); } |
|||
return inst |
|||
} |
|||
|
|||
// STRING STREAM
|
|||
|
|||
// Fed to the mode parsers, provides helper functions to make
|
|||
// parsers more succinct.
|
|||
|
|||
var StringStream = function(string, tabSize, lineOracle) { |
|||
this.pos = this.start = 0; |
|||
this.string = string; |
|||
this.tabSize = tabSize || 8; |
|||
this.lastColumnPos = this.lastColumnValue = 0; |
|||
this.lineStart = 0; |
|||
this.lineOracle = lineOracle; |
|||
}; |
|||
|
|||
StringStream.prototype.eol = function () {return this.pos >= this.string.length}; |
|||
StringStream.prototype.sol = function () {return this.pos == this.lineStart}; |
|||
StringStream.prototype.peek = function () {return this.string.charAt(this.pos) || undefined}; |
|||
StringStream.prototype.next = function () { |
|||
if (this.pos < this.string.length) |
|||
{ return this.string.charAt(this.pos++) } |
|||
}; |
|||
StringStream.prototype.eat = function (match) { |
|||
var ch = this.string.charAt(this.pos); |
|||
var ok; |
|||
if (typeof match == "string") { ok = ch == match; } |
|||
else { ok = ch && (match.test ? match.test(ch) : match(ch)); } |
|||
if (ok) {++this.pos; return ch} |
|||
}; |
|||
StringStream.prototype.eatWhile = function (match) { |
|||
var start = this.pos; |
|||
while (this.eat(match)){} |
|||
return this.pos > start |
|||
}; |
|||
StringStream.prototype.eatSpace = function () { |
|||
var start = this.pos; |
|||
while (/[\s\u00a0]/.test(this.string.charAt(this.pos))) { ++this.pos; } |
|||
return this.pos > start |
|||
}; |
|||
StringStream.prototype.skipToEnd = function () {this.pos = this.string.length;}; |
|||
StringStream.prototype.skipTo = function (ch) { |
|||
var found = this.string.indexOf(ch, this.pos); |
|||
if (found > -1) {this.pos = found; return true} |
|||
}; |
|||
StringStream.prototype.backUp = function (n) {this.pos -= n;}; |
|||
StringStream.prototype.column = function () { |
|||
if (this.lastColumnPos < this.start) { |
|||
this.lastColumnValue = countColumn(this.string, this.start, this.tabSize, this.lastColumnPos, this.lastColumnValue); |
|||
this.lastColumnPos = this.start; |
|||
} |
|||
return this.lastColumnValue - (this.lineStart ? countColumn(this.string, this.lineStart, this.tabSize) : 0) |
|||
}; |
|||
StringStream.prototype.indentation = function () { |
|||
return countColumn(this.string, null, this.tabSize) - |
|||
(this.lineStart ? countColumn(this.string, this.lineStart, this.tabSize) : 0) |
|||
}; |
|||
StringStream.prototype.match = function (pattern, consume, caseInsensitive) { |
|||
if (typeof pattern == "string") { |
|||
var cased = function (str) { return caseInsensitive ? str.toLowerCase() : str; }; |
|||
var substr = this.string.substr(this.pos, pattern.length); |
|||
if (cased(substr) == cased(pattern)) { |
|||
if (consume !== false) { this.pos += pattern.length; } |
|||
return true |
|||
} |
|||
} else { |
|||
var match = this.string.slice(this.pos).match(pattern); |
|||
if (match && match.index > 0) { return null } |
|||
if (match && consume !== false) { this.pos += match[0].length; } |
|||
return match |
|||
} |
|||
}; |
|||
StringStream.prototype.current = function (){return this.string.slice(this.start, this.pos)}; |
|||
StringStream.prototype.hideFirstChars = function (n, inner) { |
|||
this.lineStart += n; |
|||
try { return inner() } |
|||
finally { this.lineStart -= n; } |
|||
}; |
|||
StringStream.prototype.lookAhead = function (n) { |
|||
var oracle = this.lineOracle; |
|||
return oracle && oracle.lookAhead(n) |
|||
}; |
|||
StringStream.prototype.baseToken = function () { |
|||
var oracle = this.lineOracle; |
|||
return oracle && oracle.baseToken(this.pos) |
|||
}; |
|||
|
|||
// Known modes, by name and by MIME
|
|||
var modes = {}, mimeModes = {}; |
|||
|
|||
// Extra arguments are stored as the mode's dependencies, which is
|
|||
// used by (legacy) mechanisms like loadmode.js to automatically
|
|||
// load a mode. (Preferred mechanism is the require/define calls.)
|
|||
function defineMode(name, mode) { |
|||
if (arguments.length > 2) |
|||
{ mode.dependencies = Array.prototype.slice.call(arguments, 2); } |
|||
modes[name] = mode; |
|||
} |
|||
|
|||
function defineMIME(mime, spec) { |
|||
mimeModes[mime] = spec; |
|||
} |
|||
|
|||
// Given a MIME type, a {name, ...options} config object, or a name
|
|||
// string, return a mode config object.
|
|||
function resolveMode(spec) { |
|||
if (typeof spec == "string" && mimeModes.hasOwnProperty(spec)) { |
|||
spec = mimeModes[spec]; |
|||
} else if (spec && typeof spec.name == "string" && mimeModes.hasOwnProperty(spec.name)) { |
|||
var found = mimeModes[spec.name]; |
|||
if (typeof found == "string") { found = {name: found}; } |
|||
spec = createObj(found, spec); |
|||
spec.name = found.name; |
|||
} else if (typeof spec == "string" && /^[\w\-]+\/[\w\-]+\+xml$/.test(spec)) { |
|||
return resolveMode("application/xml") |
|||
} else if (typeof spec == "string" && /^[\w\-]+\/[\w\-]+\+json$/.test(spec)) { |
|||
return resolveMode("application/json") |
|||
} |
|||
if (typeof spec == "string") { return {name: spec} } |
|||
else { return spec || {name: "null"} } |
|||
} |
|||
|
|||
// Given a mode spec (anything that resolveMode accepts), find and
|
|||
// initialize an actual mode object.
|
|||
function getMode(options, spec) { |
|||
spec = resolveMode(spec); |
|||
var mfactory = modes[spec.name]; |
|||
if (!mfactory) { return getMode(options, "text/plain") } |
|||
var modeObj = mfactory(options, spec); |
|||
if (modeExtensions.hasOwnProperty(spec.name)) { |
|||
var exts = modeExtensions[spec.name]; |
|||
for (var prop in exts) { |
|||
if (!exts.hasOwnProperty(prop)) { continue } |
|||
if (modeObj.hasOwnProperty(prop)) { modeObj["_" + prop] = modeObj[prop]; } |
|||
modeObj[prop] = exts[prop]; |
|||
} |
|||
} |
|||
modeObj.name = spec.name; |
|||
if (spec.helperType) { modeObj.helperType = spec.helperType; } |
|||
if (spec.modeProps) { for (var prop$1 in spec.modeProps) |
|||
{ modeObj[prop$1] = spec.modeProps[prop$1]; } } |
|||
|
|||
return modeObj |
|||
} |
|||
|
|||
// This can be used to attach properties to mode objects from
|
|||
// outside the actual mode definition.
|
|||
var modeExtensions = {}; |
|||
function extendMode(mode, properties) { |
|||
var exts = modeExtensions.hasOwnProperty(mode) ? modeExtensions[mode] : (modeExtensions[mode] = {}); |
|||
copyObj(properties, exts); |
|||
} |
|||
|
|||
function copyState(mode, state) { |
|||
if (state === true) { return state } |
|||
if (mode.copyState) { return mode.copyState(state) } |
|||
var nstate = {}; |
|||
for (var n in state) { |
|||
var val = state[n]; |
|||
if (val instanceof Array) { val = val.concat([]); } |
|||
nstate[n] = val; |
|||
} |
|||
return nstate |
|||
} |
|||
|
|||
// Given a mode and a state (for that mode), find the inner mode and
|
|||
// state at the position that the state refers to.
|
|||
function innerMode(mode, state) { |
|||
var info; |
|||
while (mode.innerMode) { |
|||
info = mode.innerMode(state); |
|||
if (!info || info.mode == mode) { break } |
|||
state = info.state; |
|||
mode = info.mode; |
|||
} |
|||
return info || {mode: mode, state: state} |
|||
} |
|||
|
|||
function startState(mode, a1, a2) { |
|||
return mode.startState ? mode.startState(a1, a2) : true |
|||
} |
|||
|
|||
var modeMethods = { |
|||
__proto__: null, |
|||
modes: modes, |
|||
mimeModes: mimeModes, |
|||
defineMode: defineMode, |
|||
defineMIME: defineMIME, |
|||
resolveMode: resolveMode, |
|||
getMode: getMode, |
|||
modeExtensions: modeExtensions, |
|||
extendMode: extendMode, |
|||
copyState: copyState, |
|||
innerMode: innerMode, |
|||
startState: startState |
|||
}; |
|||
|
|||
// Copy StringStream and mode methods into exports (CodeMirror) object.
|
|||
exports.StringStream = StringStream; |
|||
exports.countColumn = countColumn; |
|||
for (var exported in modeMethods) { exports[exported] = modeMethods[exported]; } |
|||
|
|||
// Shim library CodeMirror with the minimal CodeMirror defined above.
|
|||
require.cache[require.resolve("../../lib/codemirror")] = require.cache[require.resolve("./runmode.node")]; |
|||
require.cache[require.resolve("../../addon/runmode/runmode")] = require.cache[require.resolve("./runmode.node")]; |
|||
|
|||
// Minimal default mode.
|
|||
exports.defineMode("null", function () { return ({token: function (stream) { return stream.skipToEnd(); }}); }); |
|||
exports.defineMIME("text/plain", "null"); |
|||
|
|||
exports.registerHelper = exports.registerGlobalHelper = Math.min; |
|||
exports.splitLines = function(string) { return string.split(/\r?\n|\r/) }; |
|||
|
|||
exports.defaults = { indentUnit: 2 }; |
|||
|
|||
// CodeMirror, copyright (c) by Marijn Haverbeke and others
|
|||
// Distributed under an MIT license: https://codemirror.net/LICENSE
|
|||
|
|||
(function(mod) { |
|||
if (typeof exports == "object" && typeof module == "object") // CommonJS
|
|||
{ mod(require("../../lib/codemirror")); } |
|||
else if (typeof define == "function" && define.amd) // AMD
|
|||
{ define(["../../lib/codemirror"], mod); } |
|||
else // Plain browser env
|
|||
{ mod(CodeMirror); } |
|||
})(function(CodeMirror) { |
|||
|
|||
CodeMirror.runMode = function(string, modespec, callback, options) { |
|||
var mode = CodeMirror.getMode(CodeMirror.defaults, modespec); |
|||
var tabSize = (options && options.tabSize) || CodeMirror.defaults.tabSize; |
|||
|
|||
// Create a tokenizing callback function if passed-in callback is a DOM element.
|
|||
if (callback.appendChild) { |
|||
var ie = /MSIE \d/.test(navigator.userAgent); |
|||
var ie_lt9 = ie && (document.documentMode == null || document.documentMode < 9); |
|||
var node = callback, col = 0; |
|||
node.innerHTML = ""; |
|||
callback = function(text, style) { |
|||
if (text == "\n") { |
|||
// Emitting LF or CRLF on IE8 or earlier results in an incorrect display.
|
|||
// Emitting a carriage return makes everything ok.
|
|||
node.appendChild(document.createTextNode(ie_lt9 ? '\r' : text)); |
|||
col = 0; |
|||
return; |
|||
} |
|||
var content = ""; |
|||
// replace tabs
|
|||
for (var pos = 0;;) { |
|||
var idx = text.indexOf("\t", pos); |
|||
if (idx == -1) { |
|||
content += text.slice(pos); |
|||
col += text.length - pos; |
|||
break; |
|||
} else { |
|||
col += idx - pos; |
|||
content += text.slice(pos, idx); |
|||
var size = tabSize - col % tabSize; |
|||
col += size; |
|||
for (var i = 0; i < size; ++i) { content += " "; } |
|||
pos = idx + 1; |
|||
} |
|||
} |
|||
// Create a node with token style and append it to the callback DOM element.
|
|||
if (style) { |
|||
var sp = node.appendChild(document.createElement("span")); |
|||
sp.className = "cm-" + style.replace(/ +/g, " cm-"); |
|||
sp.appendChild(document.createTextNode(content)); |
|||
} else { |
|||
node.appendChild(document.createTextNode(content)); |
|||
} |
|||
}; |
|||
} |
|||
|
|||
var lines = CodeMirror.splitLines(string), state = (options && options.state) || CodeMirror.startState(mode); |
|||
for (var i = 0, e = lines.length; i < e; ++i) { |
|||
if (i) { callback("\n"); } |
|||
var stream = new CodeMirror.StringStream(lines[i], null, { |
|||
lookAhead: function(n) { return lines[i + n] }, |
|||
baseToken: function() {} |
|||
}); |
|||
if (!stream.string && mode.blankLine) { mode.blankLine(state); } |
|||
while (!stream.eol()) { |
|||
var style = mode.token(stream, state); |
|||
callback(stream.current(), style, i, stream.start, state, mode); |
|||
stream.start = stream.pos; |
|||
} |
|||
} |
|||
}; |
|||
|
|||
}); |
|||
Some files were not shown because too many files changed in this diff
Loading…
Reference in new issue