Skip to content

Commit

Permalink
Add markdownlint-rule-search-replace rules
Browse files Browse the repository at this point in the history
- `missing-heading-anchor`: All headings must have anchors
- `no-absolute-links`: No absolute links allowed
- `no-curly-quotes`: No curly quotes allowed
- `no-file-extension-in-links`: Links should not have an extension
- `no-multiple-spaces`: Yeah, no multiple spaces,
- `no-punctuation-in-links`: Punctuation should not be clickable
- `no-trailing-whitespace`: Extend `MD009` to code blocks

Note: `markdownlint` rules do not apply for `translated/` files.
  • Loading branch information
its-miroma committed Jun 27, 2024
1 parent dedb892 commit f484f88
Show file tree
Hide file tree
Showing 55 changed files with 339 additions and 282 deletions.
45 changes: 41 additions & 4 deletions .markdownlint-cli2.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -32,12 +32,49 @@ config:
style: asterisk
MD053: false
MD054:
# these link styles are not easily localizable
collapsed: false # A link to [keyword][].
shortcut: false # A link to [keyword].
# [keyword]: <https://example.com>
# A link to [keyword][].
collapsed: false
# A link to [keyword].
# [keyword]: <https://docs.fabricmc.net/>
shortcut: false
url_inline: false
MD055:
style: leading_and_trailing
search-replace:
rules:
- name: missing-heading-anchor
message: "Add anchors to headings. Use lowercase characters, numbers and dashes"
searchPattern: "/^#+.*$(?<!\\{#[a-z0-9-]+\\})/gm"
searchScope: text
- name: no-absolute-links
message: "Don't use absolute links"
searchPattern: "/\\[.*?\\]\\(/(?!assets|public|reference).*?\\)/g"
searchScope: text
- name: no-curly-quotes
message: "Don't use curly quotes"
search: [“, ”, ‘, ’]
replace: ['"', '"', "'", "'"]
searchScope: text
- name: no-file-extension-in-links
message: "Don't add the file extension to links"
searchPattern: "/\\[(.*?)\\]\\((.*?)\\.(?:md|html)((?:#[a-z0-9-]+)?)\\)/g"
replace: "[$1]($2$3)"
searchScope: text
- name: no-multiple-spaces
message: "Don't use multiple spaces"
searchPattern: "/(?<!\\n| ) +(?! |\\|)/g"
replace: " "
searchScope: text
- name: no-punctuation-in-links
message: "Don't place punctuation inside of links"
searchPattern: "/(?<!@)\\[(.*?)([.,:;?!]+)\\]\\((.*?)\\)/g"
replace: "[$1]($3)$2"
searchScope: text
- name: no-trailing-whitespace
message: "Don't use trailing whitespace"
searchPattern: "/ +$/gm"
replace: ""
searchScope: code
customRules:
- ./node_modules/markdownlint-rule-search-replace/rule.js
- ./node_modules/markdownlint-rule-titlecase/rule.js
4 changes: 0 additions & 4 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,8 @@
"markdownlint.lintWorkspaceGlobs": [
"**/*.md",
"!**/node_modules",
"!**/.git",
"!versions/*/translated/**",
"!translated/**",
"!README.md"
],
"markdownlint.customRules": [
"../node_modules/markdownlint-rule-titlecase/"
]
}
46 changes: 23 additions & 23 deletions develop/codecs.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ authors:
- Syst3ms
---

# Codecs
# Codecs {#codecs}

Codec is a system for easily serializing Java objects, and is included in Mojang's DataFixerUpper (DFU)
library, which is included with Minecraft. In a modding context they can be used as an alternative
Expand All @@ -17,9 +17,9 @@ Codecs are used in conjunction with another API from DFU, `DynamicOps`. A codec
dynamic ops are used to define a format to be serialized to and from, such as json or NBT. This means any codec can be
used with any dynamic ops, and vice versa, allowing for great flexibility.

## Using Codecs
## Using Codecs {#using-codecs}

### Serializing and Deserializing
### Serializing and Deserializing {#serializing-and-deserializing}

The basic usage of a codec is to serialize and deserialize objects to and from a specific format.

Expand Down Expand Up @@ -62,7 +62,7 @@ BlockPos pos = result.resultOrPartial(LOGGER::error).orElseThrow();
LOGGER.info("Deserialized BlockPos: {}", pos);
```

### Built-in Codecs
### Built-in Codecs {#built-in-codecs}

As mentioned earlier, Mojang has already defined codecs for several vanilla and standard Java classes, including but not
limited to `BlockPos`, `BlockState`, `ItemStack`, `Identifier`, `Text`, and regex `Pattern`s. Codecs for Mojang's own
Expand All @@ -73,7 +73,7 @@ can use `Registries.BLOCK.getCodec()` to get a `Codec<Block>` which serializes t
The Codec API itself also contains some codecs for primitive types, such as `Codec.INT` and `Codec.STRING`. These are
available as statics on the `Codec` class, and are usually used as the base for more complex codecs, as explained below.

## Building Codecs
## Building Codecs {#building-codecs}

Now that we've seen how to use codecs, let's take a look at how we can build our own. Suppose we have the following
class, and we want to deserialize instances of it from json files:
Expand Down Expand Up @@ -117,7 +117,7 @@ We can get the first one from the aforementioned primitive codecs in the `Codec`
the second one can be obtained from the `Registries.ITEM` registry, which has a `getCodec()` method that returns a
`Codec<Item>`. We don't have a default codec for `List<BlockPos>`, but we can make one from `BlockPos.CODEC`.

### Lists
### Lists {#lists}

`Codec#listOf` can be used to create a list version of any codec:

Expand All @@ -126,10 +126,10 @@ Codec<List<BlockPos>> listCodec = BlockPos.CODEC.listOf();
```

It should be noted that codecs created in this way will always deserialize to an `ImmutableList`. If you need a mutable
list instead, you can make use of [xmap](#mutually-convertible-types-and-you) to convert to one during
list instead, you can make use of [xmap](#mutually-convertible-types) to convert to one during
deserialization.

### Merging Codecs for Record-Like Classes
### Merging Codecs for Record-Like Classes {#merging-codecs-for-record-like-classes}

Now that we have separate codecs for each field, we can combine them into one codec for our class using
a `RecordCodecBuilder`. This assumes that our class has a constructor containing every field we want to serialize, and
Expand Down Expand Up @@ -183,7 +183,7 @@ fields, as explained in the [Merging Codecs for Record-like Classes](#merging-co
above, they can also be turned back into regular codecs using `MapCodec#codec`, which will retain the same behavior of
boxing their input value.

#### Optional Fields
#### Optional Fields {#optional-fields}

`Codec#optionalFieldOf` can be used to create an optional map codec. This will, when the specified field is not present
in the container during deserialization, either be deserialized as an empty `Optional` or a specified default value.
Expand All @@ -202,9 +202,9 @@ the field is present, but the value is invalid, the field will always be deseria
**Since 1.20.2**, Minecraft itself (not DFU!) does however provide `Codecs#createStrictOptionalFieldCodec`,
which fails to deserialize at all if the field value is invalid.

### Constants, Constraints, and Composition
### Constants, Constraints, and Composition {#constants-constraints-composition}

#### Unit
#### Unit {#unit}

`Codec.unit` can be used to create a codec that always deserializes to a constant value, regardless of the input. When
serializing, it will do nothing.
Expand All @@ -213,7 +213,7 @@ serializing, it will do nothing.
Codec<Integer> theMeaningOfCodec = Codec.unit(42);
```

#### Numeric Ranges
#### Numeric Ranges {#numeric-ranges}

`Codec.intRange` and its pals, `Codec.floatRange` and `Codec.doubleRange` can be used to create a codec that only
accepts number values within a specified **inclusive** range. This applies to both serialization and deserialization.
Expand All @@ -223,7 +223,7 @@ accepts number values within a specified **inclusive** range. This applies to bo
Codec<Integer> amountOfFriendsYouHave = Codec.intRange(0, 2);
```

#### Pair
#### Pair {#pair}

`Codec.pair` merges two codecs, `Codec<A>` and `Codec<B>`, into a `Codec<Pair<A, B>>`. Keep in mind it only works
properly with codecs that serialize to a specific field, such as [converted `MapCodec`s](#mapcodec) or
Expand Down Expand Up @@ -253,13 +253,13 @@ Will output this json:
}
```

#### Either
#### Either {#either}

`Codec.either` combines two codecs, `Codec<A>` and `Codec<B>`, into a `Codec<Either<A, B>>`. The resulting codec will,
during deserialization, attempt to use the first codec, and _only if that fails_, attempt to use the second one.
If the second one also fails, the error of the _second_ codec will be returned.

#### Maps
#### Maps {#maps}

For processing maps with arbitrary keys, such as `HashMap`s, `Codec.unboundedMap` can be used. This returns a
`Codec<Map<K, V>>` for a given `Codec<K>` and `Codec<V>`. The resulting codec will serialize to a json object or
Expand Down Expand Up @@ -289,12 +289,12 @@ This will output this json:
```
As you can see, this works because `Identifier.CODEC` serializes directly to a string value. A similar effect can be
achieved for simple objects that don't serialize to strings by using [xmap & friends](#mutually-convertible-types-and-you) to
achieved for simple objects that don't serialize to strings by using [xmap & friends](#mutually-convertible-types) to
convert them.

### Mutually Convertible Types and You
### Mutually Convertible Types {#mutually-convertible-types}

#### `xmap`
#### `xmap` {#xmap}

Say we have two classes that can be converted to each other, but don't have a parent-child relationship. For example,
a vanilla `BlockPos` and `Vec3d`. If we have a codec for one, we can use `Codec#xmap` to create a codec for the other by
Expand All @@ -317,7 +317,7 @@ Codec<BlockPos> blockPosCodec = Vec3d.CODEC.xmap(
// method references in your `xmap` call.
```
#### flatComapMap, comapFlatMap, and flatXMap
#### flatComapMap, comapFlatMap, and flatXMap {#flatcomapmap-comapflatmap-flatxmap}
`Codec#flatComapMap`, `Codec#comapFlatMap` and `flatXMap` are similar to xmap, but they allow one or both of the
conversion functions to return a DataResult. This is useful in practice because a specific object instance may not
Expand Down Expand Up @@ -358,7 +358,7 @@ one to use:
| `Codec<A>#flatComapMap` | Yes | No |
| `Codec<A>#flatXMap` | No | No |

### Registry Dispatch
### Registry Dispatch {#registry-dispatch}

`Codec#dispatch` let us define a registry of codecs and dispatch to a specific one based on the value of a
field in the serialized data. This is very useful when deserializing objects that have different fields depending on
Expand Down Expand Up @@ -409,7 +409,7 @@ Our new codec will serialize beans to json like this, grabbing only fields that
}
```

### Recursive Codecs
### Recursive Codecs {#recursive-codecs}

Sometimes it is useful to have a codec that uses _itself_ to decode specific fields, for example when dealing with certain recursive data structures. In vanilla code, this is used for `Text` objects, which may store other `Text`s as children. Such a codec can be constructed using `Codecs#createRecursive`.

Expand Down Expand Up @@ -453,10 +453,10 @@ A serialized `ListNode` may then look like this:
}
```

## References
## References {#references}

- A much more comprehensive documentation of Codecs and related APIs can be found at the
[Unofficial DFU JavaDoc](https://kvverti.github.io/Documented-DataFixerUpper/snapshot/com/mojang/serialization/Codec.html).
[Unofficial DFU JavaDoc](https://kvverti.github.io/Documented-DataFixerUpper/snapshot/com/mojang/serialization/Codec).
- The general structure of this guide was heavily inspired by the
[Forge Community Wiki's page on Codecs](https://forge.gemwire.uk/wiki/Codecs), a more Forge-specific take on the same
topic.
8 changes: 4 additions & 4 deletions develop/commands/arguments.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ title: Command Arguments
description: Learn how to create commands with complex arguments.
---

# Command Arguments
# Command Arguments {#command-arguments}

Arguments are used in most of the commands. Sometimes they can be optional, which means if you do not provide that
argument,
Expand All @@ -28,7 +28,7 @@ both executions.

@[code lang=java highlight={3,5,6,7} transcludeWith=:::6](@/reference/latest/src/main/java/com/example/docs/command/FabricDocsReferenceCommands.java)

## Custom Argument Types
## Custom Argument Types {#custom-argument-types}

If vanilla does not have the argument type you need, you can create your own. To do this, you need to create a class that inherits the `ArgumentType<T>` interface where `T` is the type of the argument.

Expand All @@ -38,7 +38,7 @@ For example, you can create an argument type that parses a `BlockPos` from a str

@[code lang=java transcludeWith=:::1](@/reference/latest/src/main/java/com/example/docs/command/BlockPosArgumentType.java)

### Registering Custom Argument Types
### Registering Custom Argument Types {#registering-custom-argument-types}

::: warning
You need to register the custom argument type on both the server and the client or else the command will not work!
Expand All @@ -48,7 +48,7 @@ You can register your custom argument type in the `onInitialize` method of your

@[code lang=java transcludeWith=:::11](@/reference/latest/src/main/java/com/example/docs/command/FabricDocsReferenceCommands.java)

### Using Custom Argument Types
### Using Custom Argument Types {#using-custom-argument-types}

We can use our custom argument type in a command - by passing an instance of it into the `.argument` method on the command builder.

Expand Down
35 changes: 17 additions & 18 deletions develop/commands/basics.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,18 +17,19 @@ authors:
- xpple
---

# Creating Commands
# Creating Commands {#creating-commands}

Creating commands can allow a mod developer to add functionality that can be used through a command. This tutorial will
teach you how to register commands and the general command structure of Brigadier.

::: info
Brigadier is a command parser and dispatcher written by Mojang for Minecraft. It is a tree-based command library where
you
build a tree of commands and arguments. Brigadier is open source: <https://github.com/Mojang/brigadier>
you build a tree of commands and arguments.

Brigadier is open-source: <https://github.com/Mojang/brigadier>
:::

## The `Command` Interface
## The `Command` Interface {#the-command-interface}

`com.mojang.brigadier.Command` is a functional interface, which runs some specific code, and throws a
`CommandSyntaxException` in certain cases. It has a generic type `S`, which defines the type of the _command source_.
Expand All @@ -52,7 +53,7 @@ The integer can be considered the result of the command. Typically values less t
do nothing. Positive values mean the command was successful and did something. Brigadier provides a constant to indicate
success; `Command#SINGLE_SUCCESS`.

### What Can the `ServerCommandSource` Do?
### What Can the `ServerCommandSource` Do? {#what-can-the-servercommandsource-do}

A `ServerCommandSource` provides some additional implementation-specific context when a command is run. This includes
the
Expand All @@ -68,7 +69,7 @@ Command<ServerCommandSource> command = context -> {
};
```

## Registering a Basic Command
## Registering a Basic Command {#registering-a-basic-command}

Commands are registered within the `CommandRegistrationCallback` provided by the Fabric API.

Expand All @@ -80,7 +81,7 @@ The event should be registered in your mod's initializer.

The callback has three parameters:

- `CommandDispatcher<ServerCommandSource> dispatcher` - Used to register, parse and execute commands. `S` is the type
- `CommandDispatcher<ServerCommandSource> dispatcher` - Used to register, parse and execute commands. `S` is the type
of command source the command dispatcher supports.
- `CommandRegistryAccess registryAccess` - Provides an abstraction to registries that may be passed to certain command
argument methods
Expand All @@ -107,14 +108,14 @@ your own exception.

To execute this command, you must type `/foo`, which is case-sensitive.

### Registration Environment
### Registration Environment {#registration-environment}

If desired, you can also make sure a command is only registered under some specific circumstances, for example, only in
the dedicated environment:

@[code lang=java highlight={2} transcludeWith=:::2](@/reference/latest/src/main/java/com/example/docs/command/FabricDocsReferenceCommands.java)

### Command Requirements
### Command Requirements {#command-requirements}

Let's say you have a command that you only want operators to be able to execute. This is where the `requires()` method
comes into play. The `requires()` method has one argument of a `Predicate<S>` which will supply a `ServerCommandSource`
Expand All @@ -128,7 +129,7 @@ blocks. Otherwise, the command is not registered.
This has the side effect of not showing this command in tab completion to anyone who is not a level 2 operator. This is
also why you cannot tab-complete most commands when you do not enable cheats.

### Sub Commands
### Sub Commands {#sub-commands}

To add a sub command, you register the first literal node of the command normally. To have a sub command, you have to append the next literal node to the existing node.

Expand All @@ -139,23 +140,21 @@ and `/subtater subcommand` will be valid.

@[code lang=java highlight={2,8} transcludeWith=:::8](@/reference/latest/src/main/java/com/example/docs/command/FabricDocsReferenceCommands.java)

## Client Commands
## Client Commands {#client-commands}

Fabric API has a `ClientCommandManager` in `net.fabricmc.fabric.api.client.command.v2` package that can be used to register client-side commands. The code should exist only in client-side code.

@[code lang=java transcludeWith=:::1](@/reference/latest/src/client/java/com/example/docs/client/command/FabricDocsReferenceClientCommands.java)

## Command Redirects
## Command Redirects {#command-redirects}

Command redirects - also known as aliases - are a way to redirect the functionality of one command to another. This is useful for when you want to change the name of a command, but still want to support the old name.

@[code lang=java transcludeWith=:::12](@/reference/latest/src/client/java/com/example/docs/client/command/FabricDocsReferenceClientCommands.java)

## FAQ

<br>
## FAQ {#faq}

### Why Does My Code Not Compile?
### Why Does My Code Not Compile? {#why-does-my-code-not-compile}

- Catch or throw a `CommandSyntaxException` - `CommandSyntaxException` is not a `RuntimeException`. If you throw it,
that should be in methods that throw `CommandSyntaxException` in method signatures, or it should be caught.
Expand All @@ -171,7 +170,7 @@ Command redirects - also known as aliases - are a way to redirect the functional
- A Command should return an integer - When registering commands, the `executes()` method accepts a `Command` object,
which is usually a lambda. The lambda should return an integer, instead of other types.

### Can I Register Commands at Runtime?
### Can I Register Commands at Runtime? {#can-i-register-commands-at-runtime}

::: warning
You can do this, but it is not recommended. You would get the `CommandManager` from the server and add anything commands
Expand All @@ -184,7 +183,7 @@ This is required because the client locally caches the command tree it receives
are sent) for local completions-rich error messages.
:::

### Can I Unregister Commands at Runtime?
### Can I Unregister Commands at Runtime? {#can-i-unregister-commands-at-runtime}

::: warning
You can also do this, however, it is much less stable than registering commands at runtime and could cause unwanted side
Expand Down
Loading

0 comments on commit f484f88

Please sign in to comment.